diff options
author | Eugene Rozenfeld <erozen@microsoft.com> | 2018-11-23 22:37:03 -0800 |
---|---|---|
committer | Eugene Rozenfeld <erozen@microsoft.com> | 2018-12-16 11:43:48 -0800 |
commit | 3e06d9f5911ffe30894b3e08ef955f645df3acd9 (patch) | |
tree | 991b88097408eb0d11cc82493976357111ebc545 | |
parent | 1db91c5acd17384952d1e1f8e3079c2c8cfb78f6 (diff) | |
download | coreclr-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.h | 4 | ||||
-rw-r--r-- | src/jit/compiler.hpp | 12 | ||||
-rw-r--r-- | src/jit/gentree.cpp | 62 | ||||
-rw-r--r-- | src/jit/gentree.h | 6 | ||||
-rw-r--r-- | src/jit/importer.cpp | 62 | ||||
-rw-r--r-- | src/jit/objectalloc.cpp | 29 | ||||
-rw-r--r-- | tests/src/JIT/opt/ObjectStackAllocation/ObjectStackAllocationTests.csproj | 1 |
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) |