1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7XX XX
8XX ObjectAllocator XX
9XX XX
10XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12*/
13
14/*****************************************************************************/
15#ifndef OBJECTALLOC_H
16#define OBJECTALLOC_H
17/*****************************************************************************/
18
19//===============================================================================
20#include "phase.h"
21#include "smallhash.h"
22
23class ObjectAllocator final : public Phase
24{
25 typedef SmallHashTable<unsigned int, unsigned int, 8U> LocalToLocalMap;
26
27 //===============================================================================
28 // Data members
29 bool m_IsObjectStackAllocationEnabled;
30 bool m_AnalysisDone;
31 BitVecTraits m_bitVecTraits;
32 BitVec m_EscapingPointers;
33 LocalToLocalMap m_HeapLocalToStackLocalMap;
34 BitSetShortLongRep* m_ConnGraphAdjacencyMatrix;
35
36 //===============================================================================
37 // Methods
38public:
39 ObjectAllocator(Compiler* comp);
40 bool IsObjectStackAllocationEnabled() const;
41 void EnableObjectStackAllocation();
42
43protected:
44 virtual void DoPhase() override;
45
46private:
47 bool CanAllocateLclVarOnStack(unsigned int lclNum, CORINFO_CLASS_HANDLE clsHnd);
48 bool CanLclVarEscape(unsigned int lclNum);
49 void DoAnalysis();
50 void MarkLclVarAsEscaping(unsigned int lclNum);
51 bool IsLclVarEscaping(unsigned int lclNum);
52 void MarkEscapingVarsAndBuildConnGraph();
53 void AddConnGraphEdge(unsigned int sourceLclNum, unsigned int targetLclNum);
54 void ComputeEscapingNodes(BitVecTraits* bitVecTraits, BitVec& escapingNodes);
55 bool MorphAllocObjNodes();
56 void RewriteUses();
57 GenTree* MorphAllocObjNodeIntoHelperCall(GenTreeAllocObj* allocObj);
58 unsigned int MorphAllocObjNodeIntoStackAlloc(GenTreeAllocObj* allocObj, BasicBlock* block, GenTreeStmt* stmt);
59 struct BuildConnGraphVisitorCallbackData;
60 bool CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parentStack, unsigned int lclNum);
61#ifdef DEBUG
62 static Compiler::fgWalkResult AssertWhenAllocObjFoundVisitor(GenTree** pTree, Compiler::fgWalkData* data);
63#endif // DEBUG
64 static const unsigned int s_StackAllocMaxSize = 0x2000U;
65};
66
67//===============================================================================
68
69inline ObjectAllocator::ObjectAllocator(Compiler* comp)
70 : Phase(comp, "Allocate Objects", PHASE_ALLOCATE_OBJECTS)
71 , m_IsObjectStackAllocationEnabled(false)
72 , m_AnalysisDone(false)
73 , m_bitVecTraits(comp->lvaCount, comp)
74 , m_HeapLocalToStackLocalMap(comp->getAllocator())
75{
76 // Disable checks since this phase runs before fgComputePreds phase.
77 // Checks are not expected to pass before fgComputePreds.
78 doChecks = false;
79 m_EscapingPointers = BitVecOps::UninitVal();
80 m_ConnGraphAdjacencyMatrix = nullptr;
81}
82
83//------------------------------------------------------------------------
84// IsObjectStackAllocationEnabled: Returns true iff object stack allocation is enabled
85//
86// Return Value:
87// Returns true iff object stack allocation is enabled
88
89inline bool ObjectAllocator::IsObjectStackAllocationEnabled() const
90{
91 return m_IsObjectStackAllocationEnabled;
92}
93
94//------------------------------------------------------------------------
95// EnableObjectStackAllocation: Enable object stack allocation.
96
97inline void ObjectAllocator::EnableObjectStackAllocation()
98{
99 m_IsObjectStackAllocationEnabled = true;
100}
101
102//------------------------------------------------------------------------
103// CanAllocateLclVarOnStack: Returns true iff local variable can be
104// allocated on the stack.
105//
106// Arguments:
107// lclNum - Local variable number
108// clsHnd - Class handle of the variable class
109//
110// Return Value:
111// Returns true iff local variable can be allocated on the stack.
112//
113// Notes:
114// Stack allocation of objects with gc fields and boxed objects is currently disabled.
115
116inline bool ObjectAllocator::CanAllocateLclVarOnStack(unsigned int lclNum, CORINFO_CLASS_HANDLE clsHnd)
117{
118 assert(m_AnalysisDone);
119
120 DWORD classAttribs = comp->info.compCompHnd->getClassAttribs(clsHnd);
121
122 if ((classAttribs & CORINFO_FLG_CONTAINS_GC_PTR) != 0)
123 {
124 // TODO-ObjectStackAllocation: enable stack allocation of objects with gc fields
125 return false;
126 }
127
128 if ((classAttribs & CORINFO_FLG_VALUECLASS) != 0)
129 {
130 // TODO-ObjectStackAllocation: enable stack allocation of boxed structs
131 return false;
132 }
133
134 if (!comp->info.compCompHnd->canAllocateOnStack(clsHnd))
135 {
136 return false;
137 }
138
139 const unsigned int classSize = comp->info.compCompHnd->getHeapClassSize(clsHnd);
140
141 return !CanLclVarEscape(lclNum) && (classSize <= s_StackAllocMaxSize);
142}
143
144//------------------------------------------------------------------------
145// CanLclVarEscape: Returns true iff local variable can
146// potentially escape from the method
147//
148// Arguments:
149// lclNum - Local variable number
150//
151// Return Value:
152// Returns true iff local variable can potentially escape from the method
153
154inline bool ObjectAllocator::CanLclVarEscape(unsigned int lclNum)
155{
156 assert(m_AnalysisDone);
157 return BitVecOps::IsMember(&m_bitVecTraits, m_EscapingPointers, lclNum);
158}
159
160//===============================================================================
161
162#endif // OBJECTALLOC_H
163