summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Andreenko <seandree@microsoft.com>2017-04-04 16:20:29 -0700
committerGitHub <noreply@github.com>2017-04-04 16:20:29 -0700
commit60ed6841161a3b5e5e627041bc0d4a87bb21ce22 (patch)
tree0de0dac903ee5c0b614d3bd2b9eaca8be2f4a7a5 /src
parent7f296fec9799d0a2d5ace44eb468ecf264cc026f (diff)
downloadcoreclr-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.h3
-rwxr-xr-xsrc/jit/_typeinfo.h43
-rw-r--r--src/jit/compiler.h7
-rw-r--r--src/jit/flowgraph.cpp39
-rw-r--r--src/jit/importer.cpp48
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;
+}