summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Rozenfeld <erozen@microsoft.com>2018-11-23 22:37:03 -0800
committerEugene Rozenfeld <erozen@microsoft.com>2018-12-16 11:43:48 -0800
commit3e06d9f5911ffe30894b3e08ef955f645df3acd9 (patch)
tree991b88097408eb0d11cc82493976357111ebc545
parent1db91c5acd17384952d1e1f8e3079c2c8cfb78f6 (diff)
downloadcoreclr-3e06d9f5911ffe30894b3e08ef955f645df3acd9.tar.gz
coreclr-3e06d9f5911ffe30894b3e08ef955f645df3acd9.tar.bz2
coreclr-3e06d9f5911ffe30894b3e08ef955f645df3acd9.zip
Enable object stack allocation in R2R mode.
This change modified the importer to create GenTreeAllocObj node for box and newobj instead of a helper call in R2R mode. ObjectAllocator phase decides whether the object can be allocated on the stack or has to be created on the heap via a helper call. To trigger object stack allocation COMPlus_JitObjectStackAllocation has to be set (it's not set by default).
-rw-r--r--src/jit/compiler.h4
-rw-r--r--src/jit/compiler.hpp12
-rw-r--r--src/jit/gentree.cpp62
-rw-r--r--src/jit/gentree.h6
-rw-r--r--src/jit/importer.cpp62
-rw-r--r--src/jit/objectalloc.cpp29
-rw-r--r--tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.csproj1
7 files changed, 111 insertions, 65 deletions
diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index 91ea23729f..a79d77e4e2 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -2465,7 +2465,9 @@ public:
GenTreeCast* gtNewCastNodeL(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType);
- GenTree* gtNewAllocObjNode(unsigned int helper, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTree* op1);
+ GenTreeAllocObj* gtNewAllocObjNode(unsigned int helper, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTree* op1);
+
+ GenTreeAllocObj* gtNewAllocObjNode(CORINFO_RESOLVED_TOKEN* pResolvedToken, BOOL useParent);
GenTree* gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* lookupTree);
diff --git a/src/jit/compiler.hpp b/src/jit/compiler.hpp
index 39f871090c..8461b1f2a0 100644
--- a/src/jit/compiler.hpp
+++ b/src/jit/compiler.hpp
@@ -1165,12 +1165,13 @@ inline GenTreeCall* Compiler::gtNewHelperCallNode(unsigned helper, var_types typ
// Return Value:
// Returns GT_ALLOCOBJ node that will be later morphed into an
// allocation helper call or local variable allocation on the stack.
-inline GenTree* Compiler::gtNewAllocObjNode(unsigned int helper,
- CORINFO_CLASS_HANDLE clsHnd,
- var_types type,
- GenTree* op1)
+
+inline GenTreeAllocObj* Compiler::gtNewAllocObjNode(unsigned int helper,
+ CORINFO_CLASS_HANDLE clsHnd,
+ var_types type,
+ GenTree* op1)
{
- GenTree* node = new (this, GT_ALLOCOBJ) GenTreeAllocObj(type, helper, clsHnd, op1);
+ GenTreeAllocObj* node = new (this, GT_ALLOCOBJ) GenTreeAllocObj(type, helper, clsHnd, op1);
return node;
}
@@ -1184,6 +1185,7 @@ inline GenTree* Compiler::gtNewAllocObjNode(unsigned int helper,
//
// Return Value:
// New GenTreeRuntimeLookup node.
+
inline GenTree* Compiler::gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* tree)
{
assert(tree != nullptr);
diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp
index f902e4a909..ad34859547 100644
--- a/src/jit/gentree.cpp
+++ b/src/jit/gentree.cpp
@@ -6685,6 +6685,68 @@ GenTree* Compiler::gtNewBitCastNode(var_types type, GenTree* arg)
return node;
}
+//------------------------------------------------------------------------
+// gtNewAllocObjNode: Helper to create an object allocation node.
+//
+// Arguments:
+// pResolvedToken - Resolved token for the object being allocated
+// useParent - true iff the token represents a child of the object's class
+//
+// Return Value:
+// Returns GT_ALLOCOBJ node that will be later morphed into an
+// allocation helper call or local variable allocation on the stack.
+
+GenTreeAllocObj* Compiler::gtNewAllocObjNode(CORINFO_RESOLVED_TOKEN* pResolvedToken, BOOL useParent)
+{
+ const BOOL mustRestoreHandle = TRUE;
+ BOOL* const pRuntimeLookup = nullptr;
+ bool usingReadyToRunHelper = false;
+ CorInfoHelpFunc helper;
+ GenTree* opHandle = impTokenToHandle(pResolvedToken, pRuntimeLookup, mustRestoreHandle, useParent);
+
+#ifdef FEATURE_READYTORUN_COMPILER
+ CORINFO_CONST_LOOKUP lookup;
+
+ if (opts.IsReadyToRun())
+ {
+ helper = CORINFO_HELP_READYTORUN_NEW;
+ CORINFO_LOOKUP_KIND* const pGenericLookupKind = nullptr;
+ usingReadyToRunHelper =
+ info.compCompHnd->getReadyToRunHelper(pResolvedToken, pGenericLookupKind, helper, &lookup);
+ }
+#endif
+
+ if (!usingReadyToRunHelper)
+ {
+ if (opHandle == nullptr)
+ {
+ // We must be backing out of an inline.
+ assert(compDonotInline());
+ return nullptr;
+ }
+
+ helper = info.compCompHnd->getNewHelper(pResolvedToken, info.compMethodHnd);
+ }
+
+ // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call
+ // and the newfast call with a single call to a dynamic R2R cell that will:
+ // 1) Load the context
+ // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub
+ // 3) Allocate and return the new object for boxing
+ // Reason: performance (today, we'll always use the slow helper for the R2R generics case)
+
+ GenTreeAllocObj* allocObj = gtNewAllocObjNode(helper, pResolvedToken->hClass, TYP_REF, opHandle);
+
+#ifdef FEATURE_READYTORUN_COMPILER
+ if (usingReadyToRunHelper)
+ {
+ allocObj->gtEntryPoint = lookup;
+ }
+#endif
+
+ return allocObj;
+}
+
/*****************************************************************************
*
* Clones the given tree value and returns a copy of the given tree.
diff --git a/src/jit/gentree.h b/src/jit/gentree.h
index 796d723c2e..d2734d7067 100644
--- a/src/jit/gentree.h
+++ b/src/jit/gentree.h
@@ -5561,6 +5561,9 @@ struct GenTreeAllocObj final : public GenTreeUnOp
{
unsigned int gtNewHelper; // Value returned by ICorJitInfo::getNewHelper
CORINFO_CLASS_HANDLE gtAllocObjClsHnd;
+#ifdef FEATURE_READYTORUN_COMPILER
+ CORINFO_CONST_LOOKUP gtEntryPoint;
+#endif
GenTreeAllocObj(var_types type, unsigned int helper, CORINFO_CLASS_HANDLE clsHnd, GenTree* op)
: GenTreeUnOp(GT_ALLOCOBJ, type, op DEBUGARG(/*largeNode*/ TRUE))
@@ -5568,6 +5571,9 @@ struct GenTreeAllocObj final : public GenTreeUnOp
gtNewHelper(helper)
, gtAllocObjClsHnd(clsHnd)
{
+#ifdef FEATURE_READYTORUN_COMPILER
+ gtEntryPoint.addr = nullptr;
+#endif
}
#if DEBUGGABLE_GENTREE
GenTreeAllocObj() : GenTreeUnOp()
diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
index 66e240f263..52607b54b2 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -6252,36 +6252,11 @@ void Compiler::impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken)
// the opcode stack becomes empty
impBoxTempInUse = true;
-#ifdef FEATURE_READYTORUN_COMPILER
- bool usingReadyToRunHelper = false;
-
- if (opts.IsReadyToRun())
- {
- op1 = impReadyToRunHelperToTree(pResolvedToken, CORINFO_HELP_READYTORUN_NEW, TYP_REF);
- usingReadyToRunHelper = (op1 != nullptr);
- }
-
- if (!usingReadyToRunHelper)
-#endif
+ const BOOL useParent = FALSE;
+ op1 = gtNewAllocObjNode(pResolvedToken, useParent);
+ if (op1 == nullptr)
{
- // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call
- // and the newfast call with a single call to a dynamic R2R cell that will:
- // 1) Load the context
- // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub
- // 3) Allocate and return the new object for boxing
- // Reason: performance (today, we'll always use the slow helper for the R2R generics case)
-
- // Ensure that the value class is restored
- op2 = impTokenToHandle(pResolvedToken, nullptr, TRUE /* mustRestoreHandle */);
- if (op2 == nullptr)
- {
- // We must be backing out of an inline.
- assert(compDonotInline());
- return;
- }
-
- op1 = gtNewAllocObjNode(info.compCompHnd->getNewHelper(pResolvedToken, info.compMethodHnd),
- pResolvedToken->hClass, TYP_REF, op2);
+ return;
}
/* Remember that this basic block contains 'new' of an object, and so does this method */
@@ -13972,32 +13947,11 @@ void Compiler::impImportBlockCode(BasicBlock* block)
}
else
{
-#ifdef FEATURE_READYTORUN_COMPILER
- if (opts.IsReadyToRun())
- {
- op1 = impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_NEW, TYP_REF);
- usingReadyToRunHelper = (op1 != nullptr);
- }
-
- if (!usingReadyToRunHelper)
-#endif
+ const BOOL useParent = TRUE;
+ op1 = gtNewAllocObjNode(&resolvedToken, useParent);
+ if (op1 == nullptr)
{
- op1 = impParentClassTokenToHandle(&resolvedToken, nullptr, TRUE);
- if (op1 == nullptr)
- { // compDonotInline()
- return;
- }
-
- // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call
- // and the newfast call with a single call to a dynamic R2R cell that will:
- // 1) Load the context
- // 2) Perform the generic dictionary lookup and caching, and generate the appropriate
- // stub
- // 3) Allocate and return the new object
- // Reason: performance (today, we'll always use the slow helper for the R2R generics case)
-
- op1 = gtNewAllocObjNode(info.compCompHnd->getNewHelper(&resolvedToken, info.compMethodHnd),
- resolvedToken.hClass, TYP_REF, op1);
+ return;
}
// Remember that this basic block contains 'new' of an object
diff --git a/src/jit/objectalloc.cpp b/src/jit/objectalloc.cpp
index a5e240509b..736181e115 100644
--- a/src/jit/objectalloc.cpp
+++ b/src/jit/objectalloc.cpp
@@ -371,11 +371,32 @@ GenTree* ObjectAllocator::MorphAllocObjNodeIntoHelperCall(GenTreeAllocObj* alloc
{
assert(allocObj != nullptr);
- GenTree* op1 = allocObj->gtGetOp1();
+ GenTree* op1 = allocObj->gtGetOp1();
+ unsigned int helper = allocObj->gtNewHelper;
- const bool morphArgs = false;
- GenTree* helperCall =
- comp->fgMorphIntoHelperCall(allocObj, allocObj->gtNewHelper, comp->gtNewArgList(op1), morphArgs);
+ GenTreeArgList* args;
+#ifdef FEATURE_READYTORUN_COMPILER
+ CORINFO_CONST_LOOKUP entryPoint = allocObj->gtEntryPoint;
+ if (helper == CORINFO_HELP_READYTORUN_NEW)
+ {
+ args = nullptr;
+ }
+ else
+#endif
+ {
+ args = comp->gtNewArgList(op1);
+ }
+
+ const bool morphArgs = false;
+ GenTree* helperCall = comp->fgMorphIntoHelperCall(allocObj, allocObj->gtNewHelper, args, morphArgs);
+
+#ifdef FEATURE_READYTORUN_COMPILER
+ if (entryPoint.addr != nullptr)
+ {
+ assert(comp->opts.IsReadyToRun());
+ helperCall->gtCall.setEntryPoint(entryPoint);
+ }
+#endif
return helperCall;
}
diff --git a/tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.csproj b/tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.csproj
index 578b800457..cbb8b6a3c9 100644
--- a/tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.csproj
+++ b/tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.csproj
@@ -27,7 +27,6 @@
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
<PropertyGroup>
- <CrossGenTest>false</CrossGenTest>
<CLRTestBatchPreCommands>
<![CDATA[
$(CLRTestBatchPreCommands)