CORINFO_METHOD_HANDLE methHnd = call->gtCallMethHnd;
CORINFO_CLASS_HANDLE clsHnd = info.compCompHnd->getMethodClass(methHnd);
- GenTreePtr targetMethod = call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
+ GenTreePtr targetMethod = call->gtCallArgs->Rest()->Current();
noway_assert(targetMethod->TypeGet() == TYP_I_IMPL);
- genTreeOps oper = targetMethod->OperGet();
- if (oper == GT_FTN_ADDR || oper == GT_CALL || oper == GT_QMARK)
+ genTreeOps oper = targetMethod->OperGet();
+ CORINFO_METHOD_HANDLE targetMethodHnd = nullptr;
+ GenTreePtr qmarkNode = nullptr;
+ if (oper == GT_FTN_ADDR)
{
- CORINFO_METHOD_HANDLE targetMethodHnd = nullptr;
- GenTreePtr qmarkNode = nullptr;
- if (oper == GT_FTN_ADDR)
- {
- targetMethodHnd = targetMethod->gtFptrVal.gtFptrMethod;
- }
- else if (oper == GT_CALL && targetMethod->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_VIRTUAL_FUNC_PTR))
- {
- GenTreePtr handleNode = targetMethod->gtCall.gtCallArgs->gtOp.gtOp2->gtOp.gtOp2->gtOp.gtOp1;
+ targetMethodHnd = targetMethod->gtFptrVal.gtFptrMethod;
+ }
+ else if (oper == GT_CALL && targetMethod->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_VIRTUAL_FUNC_PTR))
+ {
+ GenTreePtr handleNode = targetMethod->gtCall.gtCallArgs->Rest()->Rest()->Current();
- if (handleNode->OperGet() == GT_CNS_INT)
- {
- // it's a ldvirtftn case, fetch the methodhandle off the helper for ldvirtftn. It's the 3rd arg
- targetMethodHnd = CORINFO_METHOD_HANDLE(handleNode->gtIntCon.gtCompileTimeHandle);
- }
- // Sometimes the argument to this is the result of a generic dictionary lookup, which shows
- // up as a GT_QMARK.
- else if (handleNode->OperGet() == GT_QMARK)
- {
- qmarkNode = handleNode;
- }
- }
- // Sometimes we don't call CORINFO_HELP_VIRTUAL_FUNC_PTR but instead just call
- // CORINFO_HELP_RUNTIMEHANDLE_METHOD directly.
- else if (oper == GT_QMARK)
+ if (handleNode->OperGet() == GT_CNS_INT)
{
- qmarkNode = targetMethod;
+ // it's a ldvirtftn case, fetch the methodhandle off the helper for ldvirtftn. It's the 3rd arg
+ targetMethodHnd = CORINFO_METHOD_HANDLE(handleNode->gtIntCon.gtCompileTimeHandle);
}
- if (qmarkNode)
+ // Sometimes the argument to this is the result of a generic dictionary lookup, which shows
+ // up as a GT_QMARK.
+ else if (handleNode->OperGet() == GT_QMARK)
{
- noway_assert(qmarkNode->OperGet() == GT_QMARK);
- // The argument is actually a generic dictionary lookup. For delegate creation it looks
- // like:
- // GT_QMARK
- // GT_COLON
- // op1 -> call
- // Arg 1 -> token (has compile time handle)
- // op2 -> lclvar
- //
- //
- // In this case I can find the token (which is a method handle) and that is the compile time
- // handle.
- noway_assert(qmarkNode->gtOp.gtOp2->OperGet() == GT_COLON);
- noway_assert(qmarkNode->gtOp.gtOp2->gtOp.gtOp1->OperGet() == GT_CALL);
- GenTreeCall* runtimeLookupCall = qmarkNode->gtOp.gtOp2->gtOp.gtOp1->AsCall();
-
- // This could be any of CORINFO_HELP_RUNTIMEHANDLE_(METHOD|CLASS)(_LOG?)
- GenTreePtr tokenNode = runtimeLookupCall->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
- noway_assert(tokenNode->OperGet() == GT_CNS_INT);
- targetMethodHnd = CORINFO_METHOD_HANDLE(tokenNode->gtIntCon.gtCompileTimeHandle);
+ qmarkNode = handleNode;
}
+ }
+ // Sometimes we don't call CORINFO_HELP_VIRTUAL_FUNC_PTR but instead just call
+ // CORINFO_HELP_RUNTIMEHANDLE_METHOD directly.
+ else if (oper == GT_QMARK)
+ {
+ qmarkNode = targetMethod;
+ }
+ if (qmarkNode)
+ {
+ noway_assert(qmarkNode->OperGet() == GT_QMARK);
+ // The argument is actually a generic dictionary lookup. For delegate creation it looks
+ // like:
+ // GT_QMARK
+ // GT_COLON
+ // op1 -> call
+ // Arg 1 -> token (has compile time handle)
+ // op2 -> lclvar
+ //
+ //
+ // In this case I can find the token (which is a method handle) and that is the compile time
+ // handle.
+ noway_assert(qmarkNode->gtOp.gtOp2->OperGet() == GT_COLON);
+ noway_assert(qmarkNode->gtOp.gtOp2->gtOp.gtOp1->OperGet() == GT_CALL);
+ GenTreeCall* runtimeLookupCall = qmarkNode->gtOp.gtOp2->gtOp.gtOp1->AsCall();
+
+ // This could be any of CORINFO_HELP_RUNTIMEHANDLE_(METHOD|CLASS)(_LOG?)
+ GenTreePtr tokenNode = runtimeLookupCall->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
+ noway_assert(tokenNode->OperGet() == GT_CNS_INT);
+ targetMethodHnd = CORINFO_METHOD_HANDLE(tokenNode->gtIntCon.gtCompileTimeHandle);
+ }
#ifdef FEATURE_READYTORUN_COMPILER
- if (opts.IsReadyToRun())
+ if (opts.IsReadyToRun())
+ {
+ // ReadyToRun has this optimization for a non-virtual function pointers only for now.
+ if (oper == GT_FTN_ADDR)
{
- // ReadyToRun has this optimization for a non-virtual function pointers only for now.
- if (oper == GT_FTN_ADDR)
- {
- // The first argument of the helper is delegate this pointer
- GenTreeArgList* helperArgs = gtNewArgList(call->gtCallObjp);
- CORINFO_CONST_LOOKUP entryPoint;
+ GenTreePtr thisPointer = call->gtCallObjp;
+ GenTreePtr targetObjPointers = call->gtCallArgs->Current();
+ GenTreeArgList* helperArgs = gtNewArgList(thisPointer, targetObjPointers);
- // The second argument of the helper is the target object pointers
- helperArgs->gtOp.gtOp2 = gtNewArgList(call->gtCallArgs->gtOp.gtOp1);
+ call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, GTF_EXCEPT, helperArgs);
- call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, GTF_EXCEPT, helperArgs);
- info.compCompHnd->getReadyToRunDelegateCtorHelper(targetMethod->gtFptrVal.gtLdftnResolvedToken, clsHnd,
- &entryPoint);
- call->setEntryPoint(entryPoint);
- }
+ CORINFO_RESOLVED_TOKEN* ldftnToken = targetMethod->gtFptrVal.gtLdftnResolvedToken;
+ CORINFO_CONST_LOOKUP entryPoint;
+ info.compCompHnd->getReadyToRunDelegateCtorHelper(ldftnToken, clsHnd, &entryPoint);
+ call->setEntryPoint(entryPoint);
}
- else
+ }
+ else
#endif
- if (targetMethodHnd != nullptr)
- {
- CORINFO_METHOD_HANDLE alternateCtor = nullptr;
- DelegateCtorArgs ctorData;
- ctorData.pMethod = info.compMethodHnd;
- ctorData.pArg3 = nullptr;
- ctorData.pArg4 = nullptr;
- ctorData.pArg5 = nullptr;
-
- alternateCtor = info.compCompHnd->GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, &ctorData);
- if (alternateCtor != methHnd)
- {
- // 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->gtCallMethHnd = alternateCtor;
+ if (targetMethodHnd != nullptr)
+ {
+ CORINFO_METHOD_HANDLE alternateCtor = nullptr;
+ DelegateCtorArgs ctorData;
+ ctorData.pMethod = info.compMethodHnd;
+ ctorData.pArg3 = nullptr;
+ ctorData.pArg4 = nullptr;
+ ctorData.pArg5 = nullptr;
- noway_assert(call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp2 == nullptr);
- if (ctorData.pArg3)
- {
- call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp2 =
- gtNewArgList(gtNewIconHandleNode(size_t(ctorData.pArg3), GTF_ICON_FTN_ADDR));
+ alternateCtor = info.compCompHnd->GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, &ctorData);
+ if (alternateCtor != methHnd)
+ {
+ // 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;
- if (ctorData.pArg4)
- {
- call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp2->gtOp.gtOp2 =
- gtNewArgList(gtNewIconHandleNode(size_t(ctorData.pArg4), GTF_ICON_FTN_ADDR));
+ call->gtCallMethHnd = alternateCtor;
- if (ctorData.pArg5)
- {
- call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp2->gtOp.gtOp2->gtOp.gtOp2 =
- gtNewArgList(gtNewIconHandleNode(size_t(ctorData.pArg5), GTF_ICON_FTN_ADDR));
- }
- }
- }
+ noway_assert(call->gtCallArgs->Rest()->Rest() == nullptr);
+ GenTreeArgList* addArgs = nullptr;
+ if (ctorData.pArg5)
+ {
+ GenTreePtr arg5 = gtNewIconHandleNode(size_t(ctorData.pArg5), GTF_ICON_FTN_ADDR);
+ addArgs = gtNewListNode(arg5, addArgs);
+ }
+ if (ctorData.pArg4)
+ {
+ GenTreePtr arg4 = gtNewIconHandleNode(size_t(ctorData.pArg4), GTF_ICON_FTN_ADDR);
+ addArgs = gtNewListNode(arg4, addArgs);
}
+ if (ctorData.pArg3)
+ {
+ GenTreePtr arg3 = gtNewIconHandleNode(size_t(ctorData.pArg3), GTF_ICON_FTN_ADDR);
+ addArgs = gtNewListNode(arg3, addArgs);
+ }
+ call->gtCallArgs->Rest()->Rest() = addArgs;
}
}
-
return call;
}