diff options
author | Sergey Andreenko <seandree@microsoft.com> | 2017-04-04 16:20:29 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-04 16:20:29 -0700 |
commit | 60ed6841161a3b5e5e627041bc0d4a87bb21ce22 (patch) | |
tree | 0de0dac903ee5c0b614d3bd2b9eaca8be2f4a7a5 /src | |
parent | 7f296fec9799d0a2d5ace44eb468ecf264cc026f (diff) | |
download | coreclr-60ed6841161a3b5e5e627041bc0d4a87bb21ce22.tar.gz coreclr-60ed6841161a3b5e5e627041bc0d4a87bb21ce22.tar.bz2 coreclr-60ed6841161a3b5e5e627041bc0d4a87bb21ce22.zip |
CoreRT: make CORINFO_HELP_READYTORUN_DELEGATE_CTOR optimization for verifiable sequences. (#10663)
delegate ctor optimization for CoreRT.
Diffstat (limited to 'src')
-rw-r--r-- | src/inc/corinfo.h | 3 | ||||
-rwxr-xr-x | src/jit/_typeinfo.h | 43 | ||||
-rw-r--r-- | src/jit/compiler.h | 7 | ||||
-rw-r--r-- | src/jit/flowgraph.cpp | 39 | ||||
-rw-r--r-- | src/jit/importer.cpp | 48 |
5 files changed, 129 insertions, 11 deletions
diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h index f1ff1b680c..cbc4464e1d 100644 --- a/src/inc/corinfo.h +++ b/src/inc/corinfo.h @@ -1568,6 +1568,9 @@ enum CorInfoTokenKind // token comes from CEE_NEWOBJ CORINFO_TOKENKIND_NewObj = 0x200 | CORINFO_TOKENKIND_Method, + + // token comes from CEE_LDVIRTFTN + CORINFO_TOKENKIND_Ldvirtftn = 0x400 | CORINFO_TOKENKIND_Method, }; struct CORINFO_RESOLVED_TOKEN diff --git a/src/jit/_typeinfo.h b/src/jit/_typeinfo.h index 795691ddc1..b024912dda 100755 --- a/src/jit/_typeinfo.h +++ b/src/jit/_typeinfo.h @@ -222,6 +222,9 @@ inline ti_types JITtype2tiType(CorInfoType type) // since conversions between them are not verifiable. #define TI_FLAG_NATIVE_INT 0x00000200 +// This item contains resolved token. It is used for ctor delegate optimization. +#define TI_FLAG_TOKEN 0x00000400 + // This item contains the 'this' pointer (used for tracking) #define TI_FLAG_THIS_PTR 0x00001000 @@ -289,7 +292,8 @@ private: unsigned byref : 1; // used unsigned byref_readonly : 1; // used unsigned nativeInt : 1; // used - unsigned : 2; // unused + unsigned token : 1; // used + unsigned : 1; // unused unsigned thisPtr : 1; // used unsigned thisPermHome : 1; // used unsigned generic_type_var : 1; // used @@ -300,8 +304,10 @@ private: union { CORINFO_CLASS_HANDLE m_cls; - // Valid only for type TI_METHOD + // Valid only for type TI_METHOD without IsToken CORINFO_METHOD_HANDLE m_method; + // Valid only for TI_TOKEN with IsToken + CORINFO_RESOLVED_TOKEN* m_token; }; template <typename T> @@ -365,6 +371,16 @@ public: m_method = method; } + typeInfo(CORINFO_RESOLVED_TOKEN* token) + { + assert(token != nullptr); + assert(token->hMethod != nullptr); + assert(!isInvalidHandle(token->hMethod)); + m_flags = TI_METHOD; + SetIsToken(); + m_token = token; + } + #ifdef DEBUG #if VERBOSE_VERIFY void Dump() const; @@ -444,6 +460,12 @@ public: // Operations ///////////////////////////////////////////////////////////////////////// + void SetIsToken() + { + m_flags |= TI_FLAG_TOKEN; + assert(m_bits.token); + } + void SetIsThisPtr() { m_flags |= TI_FLAG_THIS_PTR; @@ -553,9 +575,19 @@ public: CORINFO_METHOD_HANDLE GetMethod() const { assert(GetType() == TI_METHOD); + if (IsToken()) + { + return m_token->hMethod; + } return m_method; } + CORINFO_RESOLVED_TOKEN* GetToken() const + { + assert(IsToken()); + return m_token; + } + // Get this item's type // If primitive, returns the primitive type (TI_*) // If not primitive, returns: @@ -616,7 +648,7 @@ public: // Returns whether this is a method desc BOOL IsMethod() const { - return (GetType() == TI_METHOD); + return GetType() == TI_METHOD; } BOOL IsStruct() const @@ -720,6 +752,11 @@ public: return (m_flags & TI_FLAG_UNINIT_OBJREF); } + BOOL IsToken() const + { + return IsMethod() && ((m_flags & TI_FLAG_TOKEN) != 0); + } + private: // used to make functions that return typeinfo efficient. typeInfo(DWORD flags, CORINFO_CLASS_HANDLE cls) diff --git a/src/jit/compiler.h b/src/jit/compiler.h index 5e876aaa2a..1c01953f46 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -2880,6 +2880,7 @@ protected: StackEntry impPopStack(CORINFO_CLASS_HANDLE& structTypeRet); GenTreePtr impPopStack(typeInfo& ti); StackEntry& impStackTop(unsigned n = 0); + unsigned impStackHeight(); void impSaveStackState(SavedStack* savePtr, bool copy); void impRestoreStackState(SavedStack* savePtr); @@ -3384,6 +3385,8 @@ private: bool impIsImplicitTailCallCandidate( OPCODE curOpcode, const BYTE* codeAddrOfNextOpcode, const BYTE* codeEnd, int prefixFlags, bool isRecursive); + CORINFO_RESOLVED_TOKEN* impAllocateToken(CORINFO_RESOLVED_TOKEN token); + /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -4729,7 +4732,9 @@ private: void fgNoteNonInlineCandidate(GenTreeStmt* stmt, GenTreeCall* call); static fgWalkPreFn fgFindNonInlineCandidate; #endif - GenTreePtr fgOptimizeDelegateConstructor(GenTreeCall* call, CORINFO_CONTEXT_HANDLE* ExactContextHnd); + GenTreePtr fgOptimizeDelegateConstructor(GenTreeCall* call, + CORINFO_CONTEXT_HANDLE* ExactContextHnd, + CORINFO_RESOLVED_TOKEN* ldftnToken); GenTreePtr fgMorphLeaf(GenTreePtr tree); void fgAssignSetVarDef(GenTreePtr tree); GenTreePtr fgMorphOneAsgBlockOp(GenTreePtr tree); diff --git a/src/jit/flowgraph.cpp b/src/jit/flowgraph.cpp index 534cb40471..50d1cfa22d 100644 --- a/src/jit/flowgraph.cpp +++ b/src/jit/flowgraph.cpp @@ -7118,7 +7118,9 @@ bool Compiler::fgAddrCouldBeNull(GenTreePtr addr) * Optimize the call to the delegate constructor. */ -GenTreePtr Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call, CORINFO_CONTEXT_HANDLE* ExactContextHnd) +GenTreePtr Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call, + CORINFO_CONTEXT_HANDLE* ExactContextHnd, + CORINFO_RESOLVED_TOKEN* ldftnToken) { noway_assert(call->gtCallType == CT_USER_FUNC); CORINFO_METHOD_HANDLE methHnd = call->gtCallMethHnd; @@ -7182,8 +7184,37 @@ GenTreePtr Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call, CORINFO_CO #ifdef FEATURE_READYTORUN_COMPILER if (opts.IsReadyToRun()) { + if (IsTargetAbi(CORINFO_CORERT_ABI)) + { + if (ldftnToken != nullptr) + { + GenTreePtr thisPointer = call->gtCallObjp; + GenTreePtr targetObjPointers = call->gtCallArgs->Current(); + GenTreeArgList* helperArgs = nullptr; + CORINFO_LOOKUP pLookup; + CORINFO_CONST_LOOKUP entryPoint; + info.compCompHnd->getReadyToRunDelegateCtorHelper(ldftnToken, clsHnd, &pLookup); + if (!pLookup.lookupKind.needsRuntimeLookup) + { + helperArgs = gtNewArgList(thisPointer, targetObjPointers); + entryPoint = pLookup.constLookup; + } + else + { + assert(oper != GT_FTN_ADDR); + CORINFO_CONST_LOOKUP genericLookup; + info.compCompHnd->getReadyToRunHelper(ldftnToken, &pLookup.lookupKind, + CORINFO_HELP_READYTORUN_GENERIC_HANDLE, &genericLookup); + GenTreePtr ctxTree = getRuntimeContextTree(pLookup.lookupKind.runtimeLookupKind); + helperArgs = gtNewArgList(thisPointer, targetObjPointers, ctxTree); + entryPoint = genericLookup; + } + call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, GTF_EXCEPT, helperArgs); + call->setEntryPoint(entryPoint); + } + } // ReadyToRun has this optimization for a non-virtual function pointers only for now. - if (oper == GT_FTN_ADDR) + else if (oper == GT_FTN_ADDR) { GenTreePtr thisPointer = call->gtCallObjp; GenTreePtr targetObjPointers = call->gtCallArgs->Current(); @@ -7191,8 +7222,8 @@ GenTreePtr Compiler::fgOptimizeDelegateConstructor(GenTreeCall* call, CORINFO_CO call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, GTF_EXCEPT, helperArgs); - CORINFO_RESOLVED_TOKEN* ldftnToken = targetMethod->gtFptrVal.gtLdftnResolvedToken; - CORINFO_LOOKUP entryPoint; + assert(ldftnToken == targetMethod->gtFptrVal.gtLdftnResolvedToken); + CORINFO_LOOKUP entryPoint; info.compCompHnd->getReadyToRunDelegateCtorHelper(ldftnToken, clsHnd, &entryPoint); assert(!entryPoint.lookupKind.needsRuntimeLookup); call->setEntryPoint(entryPoint.constLookup); diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp index e4c740e338..11e1d470bb 100644 --- a/src/jit/importer.cpp +++ b/src/jit/importer.cpp @@ -350,6 +350,12 @@ StackEntry& Compiler::impStackTop(unsigned n) return verCurrentState.esStack[verCurrentState.esStackDepth - n - 1]; } + +unsigned Compiler::impStackHeight() +{ + return verCurrentState.esStackDepth; +} + /***************************************************************************** * Some of the trees are spilled specially. While unspilling them, or * making a copy, these need to be handled specially. The function @@ -6378,6 +6384,8 @@ var_types Compiler::impImportCall(OPCODE opcode, int tailCall = prefixFlags & PREFIX_TAILCALL; bool readonlyCall = (prefixFlags & PREFIX_READONLY) != 0; + CORINFO_RESOLVED_TOKEN* ldftnToken = nullptr; + // Synchronized methods need to call CORINFO_HELP_MON_EXIT at the end. We could // do that before tailcalls, but that is probably not the intended // semantic. So just disallow tailcalls from synchronized methods. @@ -7289,6 +7297,21 @@ var_types Compiler::impImportCall(OPCODE opcode, exactContextHnd = nullptr; } + if ((opcode == CEE_NEWOBJ) && ((clsFlags & CORINFO_FLG_DELEGATE) != 0)) + { + // Only verifiable cases are supported. + // dup; ldvirtftn; newobj; or ldftn; newobj. + // IL test could contain unverifiable sequence, in this case optimization should not be done. + if (impStackHeight() > 0) + { + typeInfo delegateTypeInfo = impStackTop().seTypeInfo; + if (delegateTypeInfo.IsToken()) + { + ldftnToken = delegateTypeInfo.GetToken(); + } + } + } + //------------------------------------------------------------------------- // The main group of arguments @@ -7369,7 +7392,7 @@ var_types Compiler::impImportCall(OPCODE opcode, { // New inliner morph it in impImportCall. // This will allow us to inline the call to the delegate constructor. - call = fgOptimizeDelegateConstructor(call->AsCall(), &exactContextHnd); + call = fgOptimizeDelegateConstructor(call->AsCall(), &exactContextHnd, ldftnToken); } if (!bIntrinsicImported) @@ -12272,7 +12295,8 @@ void Compiler::impImportBlockCode(BasicBlock* block) return; } - impPushOnStack(op1, typeInfo(resolvedToken.hMethod)); + CORINFO_RESOLVED_TOKEN* heapToken = impAllocateToken(resolvedToken); + impPushOnStack(op1, typeInfo(heapToken)); break; } @@ -12377,7 +12401,10 @@ void Compiler::impImportBlockCode(BasicBlock* block) return; } - impPushOnStack(fptr, typeInfo(resolvedToken.hMethod)); + CORINFO_RESOLVED_TOKEN* heapToken = impAllocateToken(resolvedToken); + assert(heapToken->tokenType == CORINFO_TOKENKIND_Method); + heapToken->tokenType = CORINFO_TOKENKIND_Ldvirtftn; + impPushOnStack(fptr, typeInfo(heapToken)); break; } @@ -18696,3 +18723,18 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, } #endif // defined(DEBUG) } + +//------------------------------------------------------------------------ +// impAllocateToken: create CORINFO_RESOLVED_TOKEN into jit-allocated memory and init it. +// +// Arguments: +// token - init value for the allocated token. +// +// Return Value: +// pointer to token into jit-allocated memory. +CORINFO_RESOLVED_TOKEN* Compiler::impAllocateToken(CORINFO_RESOLVED_TOKEN token) +{ + CORINFO_RESOLVED_TOKEN* memory = (CORINFO_RESOLVED_TOKEN*)compGetMem(sizeof(token)); + *memory = token; + return memory; +} |