diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/jit/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/jit/compiler.cpp | 8 | ||||
-rw-r--r-- | src/jit/compiler.h | 6 | ||||
-rw-r--r-- | src/jit/compiler.hpp | 22 | ||||
-rw-r--r-- | src/jit/compphases.h | 1 | ||||
-rw-r--r-- | src/jit/gentree.cpp | 19 | ||||
-rw-r--r-- | src/jit/gentree.h | 19 | ||||
-rw-r--r-- | src/jit/gtlist.h | 2 | ||||
-rw-r--r-- | src/jit/gtstructs.h | 1 | ||||
-rw-r--r-- | src/jit/importer.cpp | 18 | ||||
-rw-r--r-- | src/jit/jit.settings.targets | 1 | ||||
-rw-r--r-- | src/jit/jitpch.h | 2 | ||||
-rwxr-xr-x | src/jit/morph.cpp | 8 | ||||
-rw-r--r-- | src/jit/objectalloc.cpp | 204 | ||||
-rw-r--r-- | src/jit/objectalloc.h | 86 |
15 files changed, 389 insertions, 9 deletions
diff --git a/src/jit/CMakeLists.txt b/src/jit/CMakeLists.txt index b9f0c840a5..4992074443 100644 --- a/src/jit/CMakeLists.txt +++ b/src/jit/CMakeLists.txt @@ -51,6 +51,7 @@ set( JIT_SOURCES lower.cpp lsra.cpp morph.cpp + objectalloc.cpp optcse.cpp optimizer.cpp rangecheck.cpp diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp index 25b2cdc027..a79ddb3480 100644 --- a/src/jit/compiler.cpp +++ b/src/jit/compiler.cpp @@ -4151,7 +4151,15 @@ void Compiler::compCompile(void * * methodCodePtr, // Compute reachability sets and dominators. fgComputeReachability(); + } + + // Transform each GT_ALLOCOBJ node into either an allocation helper call or + // local variable allocation on the stack. + ObjectAllocator objectAllocator(this); + objectAllocator.Run(); + if (!opts.MinOpts() && !opts.compDbgCode) + { /* Perform loop inversion (i.e. transform "while" loops into "repeat" loops) and discover and classify natural loops (e.g. mark iterative loops as such). Also marks loop blocks diff --git a/src/jit/compiler.h b/src/jit/compiler.h index d7799d894b..cef9ceec76 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -1364,6 +1364,7 @@ class Compiler friend class CodeGen; friend class LclVarDsc; friend class TempDsc; + friend class ObjectAllocator; #ifndef _TARGET_64BIT_ friend class DecomposeLongs; @@ -1930,6 +1931,11 @@ public: GenTreePtr op1, var_types castType); + GenTreePtr gtNewAllocObjNode(unsigned int helper, + CORINFO_CLASS_HANDLE clsHnd, + var_types type, + GenTreePtr op1); + //------------------------------------------------------------------------ // Other GenTree functions diff --git a/src/jit/compiler.hpp b/src/jit/compiler.hpp index a74bf5e122..acf8896c72 100644 --- a/src/jit/compiler.hpp +++ b/src/jit/compiler.hpp @@ -1116,6 +1116,28 @@ GenTreeCall* Compiler::gtNewHelperCallNode(unsigned helper, return result; } +//------------------------------------------------------------------------ +// gtNewAllocObjNode: A little helper to create an object allocation node. +// +// Arguments: +// helper - Value returned by ICorJitInfo::getNewHelper +// clsHnd - Corresponding class handle +// type - Tree return type (e.g. TYP_REF) +// op1 - Node containing an address of VtablePtr +// +// Return Value: +// Returns GT_ALLOCOBJ node that will be later morphed into an +// allocation helper call or local variable allocation on the stack. +inline +GenTreePtr Compiler::gtNewAllocObjNode(unsigned int helper, + CORINFO_CLASS_HANDLE clsHnd, + var_types type, + GenTreePtr op1) +{ + GenTreePtr node = new(this, GT_ALLOCOBJ) GenTreeAllocObj(type, helper, clsHnd, op1); + return node; +} + /*****************************************************************************/ inline diff --git a/src/jit/compphases.h b/src/jit/compphases.h index 999f6cf348..f193d04647 100644 --- a/src/jit/compphases.h +++ b/src/jit/compphases.h @@ -31,6 +31,7 @@ CompPhaseNameMacro(PHASE_COMPUTE_EDGE_WEIGHTS, "Compute edge weights (1)", CompPhaseNameMacro(PHASE_CREATE_FUNCLETS, "Create EH funclets", "EH-FUNC", false, -1) #endif // FEATURE_EH_FUNCLETS CompPhaseNameMacro(PHASE_OPTIMIZE_LAYOUT, "Optimize layout", "LAYOUT", false, -1) +CompPhaseNameMacro(PHASE_ALLOCATE_OBJECTS, "Allocate Objects", "ALLOC-OBJ",false, -1) CompPhaseNameMacro(PHASE_OPTIMIZE_LOOPS, "Optimize loops", "LOOP-OPT", false, -1) CompPhaseNameMacro(PHASE_CLONE_LOOPS, "Clone loops", "LP-CLONE", false, -1) CompPhaseNameMacro(PHASE_UNROLL_LOOPS, "Unroll loops", "UNROLL", false, -1) diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp index ee8c4c8879..78c9028eaa 100644 --- a/src/jit/gentree.cpp +++ b/src/jit/gentree.cpp @@ -272,6 +272,7 @@ void GenTree::InitNodeSize() GenTree::s_gtNodeSizes[GT_LEA ] = TREE_NODE_SZ_LARGE; GenTree::s_gtNodeSizes[GT_COPYOBJ ] = TREE_NODE_SZ_LARGE; GenTree::s_gtNodeSizes[GT_INTRINSIC ] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_ALLOCOBJ ] = TREE_NODE_SZ_LARGE; #if USE_HELPERS_FOR_INT_DIV GenTree::s_gtNodeSizes[GT_DIV ] = TREE_NODE_SZ_LARGE; GenTree::s_gtNodeSizes[GT_UDIV ] = TREE_NODE_SZ_LARGE; @@ -341,6 +342,7 @@ void GenTree::InitNodeSize() static_assert_no_msg(sizeof(GenTreeArgPlace) <= TREE_NODE_SZ_SMALL); static_assert_no_msg(sizeof(GenTreeLabel) <= TREE_NODE_SZ_SMALL); static_assert_no_msg(sizeof(GenTreePhiArg) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeAllocObj) <= TREE_NODE_SZ_LARGE); // *** large node #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_SMALL); #else // FEATURE_UNIX_AMD64_STRUCT_PASSING @@ -2145,7 +2147,10 @@ AGAIN: case GT_INDEX: hash += tree->gtIndex.gtIndElemSize; break; - + case GT_ALLOCOBJ: + hash = genTreeHashAdd(hash, static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtAllocObj.gtAllocObjClsHnd))); + hash = genTreeHashAdd(hash, tree->gtAllocObj.gtNewHelper); + break; // For the ones below no extra argument matters for comparison. case GT_BOX: @@ -6754,6 +6759,13 @@ GenTreePtr Compiler::gtCloneExpr(GenTree * tree, } break; + case GT_ALLOCOBJ: + { + GenTreeAllocObj* asAllocObj = tree->AsAllocObj(); + copy = new (this, GT_ALLOCOBJ) GenTreeAllocObj(tree->TypeGet(), asAllocObj->gtNewHelper, asAllocObj->gtAllocObjClsHnd, asAllocObj->gtOp1); + } + break; + case GT_ARR_LENGTH: copy = new (this, GT_ARR_LENGTH) GenTreeArrLen(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtArrLen.ArrLenOffset()); break; @@ -11062,6 +11074,11 @@ GenTreePtr Compiler::gtFoldExprConst(GenTreePtr tree) } #endif // FEATURE_SIMD + if (tree->gtOper == GT_ALLOCOBJ) + { + return tree; + } + if (kind & GTK_UNOP) { assert(op1->OperKind() & GTK_CONST); diff --git a/src/jit/gentree.h b/src/jit/gentree.h index 5db3d726aa..9058997f6a 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -4221,6 +4221,25 @@ struct GenTreeCopyOrReload : public GenTreeUnOp #endif }; +// Represents GT_ALLOCOBJ node + +struct GenTreeAllocObj final : public GenTreeUnOp +{ + unsigned int gtNewHelper; // Value returned by ICorJitInfo::getNewHelper + CORINFO_CLASS_HANDLE gtAllocObjClsHnd; + + GenTreeAllocObj(var_types type, unsigned int helper, CORINFO_CLASS_HANDLE clsHnd, GenTreePtr op) : + GenTreeUnOp(GT_ALLOCOBJ, type, op + DEBUGARG(/*largeNode*/TRUE)),// This node in most cases will be changed to a call node + gtNewHelper(helper), + gtAllocObjClsHnd(clsHnd) + {} +#if DEBUGGABLE_GENTREE + GenTreeAllocObj() : GenTreeUnOp() {} +#endif +}; + + //------------------------------------------------------------------------ // Deferred inline functions of GenTree -- these need the subtypes above to // be defined already. diff --git a/src/jit/gtlist.h b/src/jit/gtlist.h index b56952a4b2..97db5b3c0e 100644 --- a/src/jit/gtlist.h +++ b/src/jit/gtlist.h @@ -85,6 +85,8 @@ GTNODE(SIMD_CHK , "simdChk" ,0,GTK_SPECIAL) // Compare wheth // does the compare, so that it can be more easily optimized. But that involves generating qmarks at import time... #endif // FEATURE_SIMD +GTNODE(ALLOCOBJ , "allocObj" ,0,GTK_UNOP|GTK_EXOP) // object allocator + //----------------------------------------------------------------------------- // Binary operators (2 operands): //----------------------------------------------------------------------------- diff --git a/src/jit/gtstructs.h b/src/jit/gtstructs.h index c76e69f417..ae7311ace5 100644 --- a/src/jit/gtstructs.h +++ b/src/jit/gtstructs.h @@ -101,6 +101,7 @@ GTSTRUCT_1(CpBlk , GT_COPYBLK) #ifdef FEATURE_SIMD GTSTRUCT_1(SIMD , GT_SIMD) #endif // FEATURE_SIMD +GTSTRUCT_1(AllocObj , GT_ALLOCOBJ) /*****************************************************************************/ #undef GTSTRUCT_0 #undef GTSTRUCT_1 diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp index 445844eabe..038fb98ab2 100644 --- a/src/jit/importer.cpp +++ b/src/jit/importer.cpp @@ -11852,18 +11852,22 @@ DO_LDFTN: // 3) Allocate and return the new object // Reason: performance (today, we'll always use the slow helper for the R2R generics case) - op1 = gtNewHelperCallNode( info.compCompHnd->getNewHelper(&resolvedToken, info.compMethodHnd), - TYP_REF, 0, - gtNewArgList(op1)); + op1 = gtNewAllocObjNode( info.compCompHnd->getNewHelper(&resolvedToken, info.compMethodHnd), + resolvedToken.hClass, TYP_REF, op1 ); } - /* Remember that this basic block contains 'new' of an object */ + // Remember that this basic block contains 'new' of an object block->bbFlags |= BBF_HAS_NEWOBJ; optMethodFlags |= OMF_HAS_NEWOBJ; - /* Append the assignment to the temp/local. Dont need to spill - at all as we are just calling an EE-Jit helper which can only - cause an (async) OutOfMemoryException */ + // Append the assignment to the temp/local. Dont need to spill + // at all as we are just calling an EE-Jit helper which can only + // cause an (async) OutOfMemoryException. + + // We assign the newly allocated object (by a GT_ALLOCOBJ node) + // to a temp. Note that the pattern "temp = allocObj" is required + // by ObjectAllocator phase to be able to determine GT_ALLOCOBJ nodes + // without exhaustive walk over all expressions. impAssignTempGen(lclNum, op1, (unsigned)CHECK_SPILL_NONE); diff --git a/src/jit/jit.settings.targets b/src/jit/jit.settings.targets index 2ffcfcb69c..b8e109e761 100644 --- a/src/jit/jit.settings.targets +++ b/src/jit/jit.settings.targets @@ -84,6 +84,7 @@ <CppCompile Include="..\inlinepolicy.cpp" /> <CppCompile Include="..\jitconfig.cpp" /> <CppCompile Include="..\hostallocator.cpp" /> + <CppCompile Include="..\objectalloc.cpp" /> <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='True'" Include="..\CodeGenLegacy.cpp" /> <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\Lower.cpp" /> <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\LSRA.cpp" /> diff --git a/src/jit/jitpch.h b/src/jit/jitpch.h index 58c9c6bd95..e7966de92e 100644 --- a/src/jit/jitpch.h +++ b/src/jit/jitpch.h @@ -34,4 +34,4 @@ #include "blockset.h" #include "bitvec.h" #include "inline.h" - +#include "objectalloc.h" diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp index 9570d48518..33dfb6dcfc 100755 --- a/src/jit/morph.cpp +++ b/src/jit/morph.cpp @@ -64,6 +64,8 @@ GenTreePtr Compiler::fgMorphIntoHelperCall(GenTreePtr tree, tree->ChangeOper(GT_CALL); tree->gtFlags |= GTF_CALL; + if (args) + tree->gtFlags |= (args->gtFlags & GTF_ALL_EFFECT); tree->gtCall.gtCallType = CT_HELPER; tree->gtCall.gtCallMethHnd = eeFindHelper(helper); tree->gtCall.gtCallArgs = args; @@ -79,6 +81,12 @@ GenTreePtr Compiler::fgMorphIntoHelperCall(GenTreePtr tree, tree->gtCall.gtCallRegUsedMask = RBM_NONE; #endif // LEGACY_BACKEND +#if DEBUG + // Helper calls are never candidates. + + tree->gtCall.gtInlineObservation = InlineObservation::CALLSITE_IS_CALL_TO_HELPER; +#endif // DEBUG + #ifdef FEATURE_READYTORUN_COMPILER tree->gtCall.gtEntryPoint.addr = nullptr; #endif diff --git a/src/jit/objectalloc.cpp b/src/jit/objectalloc.cpp new file mode 100644 index 0000000000..38a441c6f0 --- /dev/null +++ b/src/jit/objectalloc.cpp @@ -0,0 +1,204 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XX XX +XX ObjectAllocator XX +XX XX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +*/ + +#include "jitpch.h" +#ifdef _MSC_VER +#pragma hdrstop +#endif + +//=============================================================================== + +//------------------------------------------------------------------------ +// DoPhase: Run analysis (if object stack allocation is enabled) and then +// morph each GT_ALLOCOBJ node either into an allocation helper +// call or stack allocation. +// Notes: +// Runs only if Compiler::optMethodFlags has flag OMF_HAS_NEWOBJ set. +void ObjectAllocator::DoPhase() +{ + if ((comp->optMethodFlags & OMF_HAS_NEWOBJ) == 0) + { + return; + } + + if (IsObjectStackAllocationEnabled()) + { + DoAnalysis(); + } + + MorphAllocObjNodes(); +} + +//------------------------------------------------------------------------ +// DoAnalysis: Walk over basic blocks of the method and detect all local +// variables that can be allocated on the stack. +// +// Assumptions: +// Must be run after the dominators have been computed (we need this +// information to detect loops). +void ObjectAllocator::DoAnalysis() +{ + assert(m_IsObjectStackAllocationEnabled); + assert(comp->fgDomsComputed); + // TODO-ObjectStackAllocation + NYI("DoAnalysis"); +} + +//------------------------------------------------------------------------ +// MorphAllocObjNodes: Morph each GT_ALLOCOBJ node either into an +// allocation helper call or stack allocation. +// +// Notes: +// Runs only over the blocks having bbFlags BBF_HAS_NEWOBJ set. +void ObjectAllocator::MorphAllocObjNodes() +{ + BasicBlock* block; + + foreach_block(comp, block) + { + if ((block->bbFlags & BBF_HAS_NEWOBJ) == 0) + { + continue; + } + + for (GenTreeStmt* stmt = block->firstStmt(); + stmt; + stmt = stmt->gtNextStmt) + { + GenTreePtr stmtExpr = stmt->gtStmtExpr; + GenTreePtr op2 = nullptr; + + bool canonicalAllocObjFound = false; + + if (stmtExpr->OperGet() == GT_ASG && stmtExpr->TypeGet() == TYP_REF) + { + op2 = stmtExpr->gtGetOp2(); + + if (op2->OperGet() == GT_ALLOCOBJ) + { + canonicalAllocObjFound = true; + } + } + + if (canonicalAllocObjFound) + { + //------------------------------------------------------------------------ + // We expect the following expression tree at this point + // * GT_STMT void (top level) + // | /--* GT_ALLOCOBJ ref + // \--* GT_ASG ref + // \--* GT_LCL_VAR ref + //------------------------------------------------------------------------ + + GenTreePtr op1 = stmtExpr->gtGetOp1(); + + assert(op1->OperGet() == GT_LCL_VAR); + assert(op1->TypeGet() == TYP_REF); + assert(op2 != nullptr); + assert(op2->OperGet() == GT_ALLOCOBJ); + + GenTreeAllocObj* asAllocObj = op2->AsAllocObj(); + unsigned int lclNum = op1->AsLclVar()->GetLclNum(); + + if (IsObjectStackAllocationEnabled() && CanAllocateLclVarOnStack(lclNum)) + { + op2 = MorphAllocObjNodeIntoStackAlloc(asAllocObj, block, stmt); + } + else + { + op2 = MorphAllocObjNodeIntoHelperCall(asAllocObj); + } + + // Propagate flags of op2 to its parent. + stmtExpr->gtOp.gtOp2 = op2; + stmtExpr->gtFlags |= op2->gtFlags & GTF_ALL_EFFECT; + } +#ifdef DEBUG + else + { + // We assume that GT_ALLOCOBJ nodes are always present in the + // canonical form. + comp->fgWalkTreePre(&stmt->gtStmtExpr, AssertWhenAllocObjFoundVisitor); + } +#endif // DEBUG + } + } +} + +//------------------------------------------------------------------------ +// MorphAllocObjNodeIntoHelperCall: Morph a GT_ALLOCOBJ node into an +// allocation helper call. +// +// Arguments: +// allocObj - GT_ALLOCOBJ that will be replaced by helper call. +// +// Return Value: +// Address of helper call node (can be the same as allocObj). +// +// Notes: +// Must update parents flags after this. +GenTreePtr ObjectAllocator::MorphAllocObjNodeIntoHelperCall(GenTreeAllocObj* allocObj) +{ + assert(allocObj != nullptr); + + GenTreePtr op1 = allocObj->gtGetOp1(); + + GenTreePtr helperCall = comp->fgMorphIntoHelperCall( + allocObj, allocObj->gtNewHelper, comp->gtNewArgList(op1)); + + return helperCall; +} + +//------------------------------------------------------------------------ +// MorphAllocObjNodeIntoStackAlloc: Morph a GT_ALLOCOBJ node into stack +// allocation. +// Arguments: +// allocObj - GT_ALLOCOBJ that will be replaced by helper call. +// block - a basic block where allocObj is +// stmt - a statement where allocObj is +// +// Return Value: +// Address of tree doing stack allocation (can be the same as allocObj). +// +// Notes: +// Must update parents flags after this. +// This function can insert additional statements before stmt. +GenTreePtr ObjectAllocator::MorphAllocObjNodeIntoStackAlloc(GenTreeAllocObj* allocObj, BasicBlock* block, GenTreeStmt* stmt) +{ + assert(allocObj != nullptr); + assert(m_AnalysisDone); + + // TODO-StackAllocation + NYI("MorphAllocObjIntoStackAlloc"); + + return allocObj; +} + +#ifdef DEBUG + +//------------------------------------------------------------------------ +// AssertWhenAllocObjFoundVisitor: Look for a GT_ALLOCOBJ node and assert +// when found one. +Compiler::fgWalkResult ObjectAllocator::AssertWhenAllocObjFoundVisitor(GenTreePtr* pTree, Compiler::fgWalkData* data) +{ + GenTreePtr tree = *pTree; + + assert(tree != nullptr); + assert(tree->OperGet() != GT_ALLOCOBJ); + + return Compiler::fgWalkResult::WALK_CONTINUE; +} + +#endif // DEBUG + +//=============================================================================== diff --git a/src/jit/objectalloc.h b/src/jit/objectalloc.h new file mode 100644 index 0000000000..a9707f326d --- /dev/null +++ b/src/jit/objectalloc.h @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XX XX +XX ObjectAllocator XX +XX XX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +*/ + +/*****************************************************************************/ +#ifndef OBJECTALLOC_H +#define OBJECTALLOC_H +/*****************************************************************************/ + +//=============================================================================== +#include "phase.h" + +class ObjectAllocator final : public Phase +{ + //=============================================================================== + // Data members + bool m_IsObjectStackAllocationEnabled; + bool m_AnalysisDone; + //=============================================================================== + // Methods +public: + ObjectAllocator(Compiler* comp); + bool IsObjectStackAllocationEnabled() const; + void EnableObjectStackAllocation(); + +protected: + virtual void DoPhase() override; + +private: + bool CanAllocateLclVarOnStack(unsigned int lclNum) const; + void DoAnalysis(); + void MorphAllocObjNodes(); + GenTreePtr MorphAllocObjNodeIntoHelperCall(GenTreeAllocObj* allocObj); + GenTreePtr MorphAllocObjNodeIntoStackAlloc(GenTreeAllocObj* allocObj, BasicBlock* block, GenTreeStmt* stmt); +#ifdef DEBUG + static Compiler::fgWalkResult AssertWhenAllocObjFoundVisitor(GenTreePtr* pTree, Compiler::fgWalkData* data); +#endif // DEBUG +}; + +//=============================================================================== + +inline +ObjectAllocator::ObjectAllocator(Compiler* comp) : + Phase(comp, "Allocate Objects", PHASE_ALLOCATE_OBJECTS), + m_IsObjectStackAllocationEnabled(false), + m_AnalysisDone(false) +{ +} + +inline +bool ObjectAllocator::IsObjectStackAllocationEnabled() const +{ + return m_IsObjectStackAllocationEnabled; +} + +inline +void ObjectAllocator::EnableObjectStackAllocation() +{ + m_IsObjectStackAllocationEnabled = true; +} + +//------------------------------------------------------------------------ +// CanAllocateLclVarOnStack: Returns true iff local variable can not +// potentially escape from the method and +// can be allocated on the stack. +inline +bool ObjectAllocator::CanAllocateLclVarOnStack(unsigned int lclNum) const +{ + assert(m_AnalysisDone); + // TODO-ObjectStackAllocation + NYI("CanAllocateLclVarOnStack"); + return false; +} + +//=============================================================================== + +#endif // OBJECTALLOC_H |