Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit b51ff00

Browse files
committed
Address code review feedback.
1 parent 70e43ab commit b51ff00

File tree

6 files changed

+113
-103
lines changed

6 files changed

+113
-103
lines changed

src/jit/compmemkind.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ CompMemKindMacro(Unknown)
5353
CompMemKindMacro(RangeCheck)
5454
CompMemKindMacro(CopyProp)
5555
CompMemKindMacro(SideEffects)
56+
CompMemKindMacro(ObjectAllocator)
5657
//clang-format on
5758

5859
#undef CompMemKindMacro

src/jit/morph.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16734,10 +16734,14 @@ void Compiler::fgMorph()
1673416734
// local variable allocation on the stack.
1673516735
ObjectAllocator objectAllocator(this); // PHASE_ALLOCATE_OBJECTS
1673616736

16737+
// TODO-ObjectStackAllocation: Enable the optimization for architectures using
16738+
// JIT32_GCENCODER (i.e., x86).
16739+
#ifndef JIT32_GCENCODER
1673716740
if (JitConfig.JitObjectStackAllocation() && !opts.MinOpts() && !opts.compDbgCode)
1673816741
{
1673916742
objectAllocator.EnableObjectStackAllocation();
1674016743
}
16744+
#endif // JIT32_GCENCODER
1674116745

1674216746
objectAllocator.Run();
1674316747

src/jit/objectalloc.cpp

Lines changed: 87 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,6 @@ void ObjectAllocator::DoPhase()
5353
}
5454
}
5555

56-
struct ObjectAllocator::BuildConnGraphVisitorCallbackData
57-
{
58-
BuildConnGraphVisitorCallbackData(ObjectAllocator* objectAllocator) : m_objectAllocator(objectAllocator)
59-
{
60-
}
61-
62-
ObjectAllocator* m_objectAllocator;
63-
};
64-
6556
//------------------------------------------------------------------------------
6657
// MarkLclVarAsEscaping : Mark local variable as escaping.
6758
//
@@ -114,7 +105,7 @@ void ObjectAllocator::DoAnalysis()
114105
if (comp->lvaCount > 0)
115106
{
116107
m_EscapingPointers = BitVecOps::MakeEmpty(&m_bitVecTraits);
117-
m_ConnGraphAdjacencyMatrix = new (comp->getAllocator()) BitSetShortLongRep[comp->lvaCount];
108+
m_ConnGraphAdjacencyMatrix = new (comp->getAllocator(CMK_ObjectAllocator)) BitSetShortLongRep[comp->lvaCount];
118109

119110
MarkEscapingVarsAndBuildConnGraph();
120111
ComputeEscapingNodes(&m_bitVecTraits, m_EscapingPointers);
@@ -141,7 +132,47 @@ void ObjectAllocator::DoAnalysis()
141132

142133
void ObjectAllocator::MarkEscapingVarsAndBuildConnGraph()
143134
{
144-
BuildConnGraphVisitorCallbackData callbackData(this);
135+
class BuildConnGraphVisitor final : public GenTreeVisitor<BuildConnGraphVisitor>
136+
{
137+
ObjectAllocator* m_allocator;
138+
139+
public:
140+
enum
141+
{
142+
DoPreOrder = true,
143+
DoLclVarsOnly = true,
144+
ComputeStack = true,
145+
};
146+
147+
BuildConnGraphVisitor(ObjectAllocator* allocator)
148+
: GenTreeVisitor<BuildConnGraphVisitor>(allocator->comp), m_allocator(allocator)
149+
{
150+
}
151+
152+
Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
153+
{
154+
GenTree* tree = *use;
155+
assert(tree != nullptr);
156+
assert(tree->IsLocal());
157+
158+
var_types type = tree->TypeGet();
159+
if ((tree->OperGet() == GT_LCL_VAR) && (type == TYP_REF || type == TYP_BYREF || type == TYP_I_IMPL))
160+
{
161+
unsigned int lclNum = tree->AsLclVar()->GetLclNum();
162+
assert(tree == m_ancestors.Index(0));
163+
164+
if (m_allocator->CanLclVarEscapeViaParentStack(&m_ancestors, lclNum))
165+
{
166+
if (!m_allocator->IsLclVarEscaping(lclNum))
167+
{
168+
JITDUMP("V%02u first escapes via [%06u]\n", lclNum, m_compiler->dspTreeID(tree));
169+
}
170+
m_allocator->MarkLclVarAsEscaping(lclNum);
171+
}
172+
}
173+
return Compiler::fgWalkResult::WALK_CONTINUE;
174+
}
175+
};
145176

146177
for (unsigned int lclNum = 0; lclNum < comp->lvaCount; ++lclNum)
147178
{
@@ -170,10 +201,8 @@ void ObjectAllocator::MarkEscapingVarsAndBuildConnGraph()
170201
{
171202
for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
172203
{
173-
const bool lclVarsOnly = true;
174-
const bool computeStack = true;
175-
176-
comp->fgWalkTreePre(&stmt->gtStmtExpr, BuildConnGraphVisitor, &callbackData, lclVarsOnly, computeStack);
204+
BuildConnGraphVisitor buildConnGraphVisitor(this);
205+
buildConnGraphVisitor.WalkTree(&stmt->gtStmtExpr, nullptr);
177206
}
178207
}
179208
}
@@ -423,55 +452,13 @@ unsigned int ObjectAllocator::MorphAllocObjNodeIntoStackAlloc(GenTreeAllocObj* a
423452
return lclNum;
424453
}
425454

426-
//------------------------------------------------------------------------
427-
// BuildConnGraphVisitor: Check if the current tree is a local variable that can point to an object
428-
// and is escaping. Update the connection graph as necessary.
429-
//
430-
// Arguments:
431-
// pTree - Tree being visited
432-
// data - Walker data
433-
//
434-
// Return Value:
435-
// Always returns fgWalkResult::WALK_CONTINUE
436-
437-
Compiler::fgWalkResult ObjectAllocator::BuildConnGraphVisitor(GenTree** pTree, Compiler::fgWalkData* data)
438-
{
439-
GenTree* tree = *pTree;
440-
assert(tree);
441-
442-
var_types type = tree->TypeGet();
443-
if (tree->OperGet() == GT_LCL_VAR && (type == TYP_REF || type == TYP_BYREF || type == TYP_I_IMPL))
444-
{
445-
Compiler* compiler = data->compiler;
446-
GenTree* parent = data->parent;
447-
BuildConnGraphVisitorCallbackData* callbackData =
448-
reinterpret_cast<BuildConnGraphVisitorCallbackData*>(data->pCallbackData);
449-
ObjectAllocator* objectAllocator = callbackData->m_objectAllocator;
450-
451-
unsigned int lclNum = tree->AsLclVar()->GetLclNum();
452-
assert(tree == data->parentStack->Index(0));
453-
assert(data->parent == data->parentStack->Index(1));
454-
455-
if (objectAllocator->CanLclVarEscapeViaParentStack(data->parentStack, lclNum, data->compiler))
456-
{
457-
if (!objectAllocator->IsLclVarEscaping(lclNum))
458-
{
459-
JITDUMP("V%02u first escapes (2) via [%06u]\n", lclNum, tree->gtTreeID);
460-
}
461-
objectAllocator->MarkLclVarAsEscaping(lclNum);
462-
}
463-
}
464-
return Compiler::fgWalkResult::WALK_CONTINUE;
465-
}
466-
467455
//------------------------------------------------------------------------
468456
// CanLclVarEscapeViaParentStack: Check if the local variable escapes via the given parent stack.
469457
// Update the connection graph as necessary.
470458
//
471459
// Arguments:
472460
// parentStack - Parent stack of the current visit
473461
// lclNum - Local variable number
474-
// compiler - Compiler instance
475462
//
476463
// Return Value:
477464
// true if the local can escape via the parent stack; false otherwise
@@ -480,17 +467,15 @@ Compiler::fgWalkResult ObjectAllocator::BuildConnGraphVisitor(GenTree** pTree, C
480467
// The method currently treats all locals assigned to a field as escaping.
481468
// The can potentially be tracked by special field edges in the connection graph.
482469

483-
bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parentStack,
484-
unsigned int lclNum,
485-
Compiler* compiler)
470+
bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parentStack, unsigned int lclNum)
486471
{
487472
assert(parentStack != nullptr);
488473
int parentIndex = 1;
489474

490-
bool done = false;
475+
bool keepChecking = true;
491476
bool canLclVarEscapeViaParentStack = true;
492477

493-
while (!done)
478+
while (keepChecking)
494479
{
495480
if (parentStack->Height() <= parentIndex)
496481
{
@@ -501,7 +486,7 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parent
501486
canLclVarEscapeViaParentStack = true;
502487
GenTree* tree = parentStack->Index(parentIndex - 1);
503488
GenTree* parent = parentStack->Index(parentIndex);
504-
done = true;
489+
keepChecking = false;
505490

506491
switch (parent->OperGet())
507492
{
@@ -566,7 +551,7 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parent
566551
case GT_ADD:
567552
// Check whether the local escapes via its grandparent.
568553
++parentIndex;
569-
done = false;
554+
keepChecking = true;
570555
break;
571556

572557
case GT_FIELD:
@@ -578,7 +563,7 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parent
578563
{
579564
// Check if the address of the field/ind escapes.
580565
parentIndex += 2;
581-
done = false;
566+
keepChecking = true;
582567
}
583568
else
584569
{
@@ -594,7 +579,7 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parent
594579

595580
if (asCall->gtCallType == CT_HELPER)
596581
{
597-
const CorInfoHelpFunc helperNum = compiler->eeGetHelperNum(asCall->gtCallMethHnd);
582+
const CorInfoHelpFunc helperNum = comp->eeGetHelperNum(asCall->gtCallMethHnd);
598583

599584
if (Compiler::s_helperCallProperties.IsPure(helperNum))
600585
{
@@ -644,46 +629,50 @@ Compiler::fgWalkResult ObjectAllocator::AssertWhenAllocObjFoundVisitor(GenTree**
644629

645630
void ObjectAllocator::RewriteUses()
646631
{
647-
BasicBlock* block;
648-
649-
foreach_block(comp, block)
632+
class RewriteUsesVisitor final : public GenTreeVisitor<RewriteUsesVisitor>
650633
{
651-
for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
634+
ObjectAllocator* m_allocator;
635+
636+
public:
637+
enum
652638
{
653-
const bool lclVarsOnly = true;
654-
const bool computeStack = false;
639+
DoPreOrder = true,
640+
DoLclVarsOnly = true,
641+
};
655642

656-
comp->fgWalkTreePre(&stmt->gtStmtExpr, RewriteUsesVisitor, this, lclVarsOnly, computeStack);
643+
RewriteUsesVisitor(ObjectAllocator* allocator)
644+
: GenTreeVisitor<RewriteUsesVisitor>(allocator->comp), m_allocator(allocator)
645+
{
657646
}
658-
}
659-
}
660647

661-
//------------------------------------------------------------------------
662-
// RewriteUsesVisitor: Replace a use of the newobj temp with address of the stack local.
663-
//
664-
// Arguments:
665-
// pTree - Tree to examine
666-
// data - Walker data
667-
//
668-
// Return Value:
669-
// Always returns fgWalkResult::WALK_CONTINUE
648+
Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
649+
{
650+
GenTree* tree = *use;
651+
assert(tree != nullptr);
652+
assert(tree->IsLocal());
670653

671-
Compiler::fgWalkResult ObjectAllocator::RewriteUsesVisitor(GenTree** pTree, Compiler::fgWalkData* data)
672-
{
673-
ObjectAllocator* allocator = reinterpret_cast<ObjectAllocator*>(data->pCallbackData);
674-
GenTree* tree = *pTree;
675-
assert(tree != nullptr);
676-
assert(tree->IsLocal());
654+
const unsigned int lclNum = tree->AsLclVarCommon()->gtLclNum;
655+
unsigned int newLclNum = BAD_VAR_NUM;
656+
657+
if (m_allocator->m_HeapLocalToStackLocalMap.TryGetValue(lclNum, &newLclNum))
658+
{
659+
GenTree* newTree =
660+
m_compiler->gtNewOperNode(GT_ADDR, TYP_BYREF, m_compiler->gtNewLclvNode(newLclNum, TYP_STRUCT));
661+
*use = newTree;
662+
}
677663

678-
const unsigned int lclNum = tree->AsLclVarCommon()->gtLclNum;
679-
unsigned int newLclNum = BAD_VAR_NUM;
680-
Compiler* comp = allocator->comp;
664+
return Compiler::fgWalkResult::WALK_CONTINUE;
665+
}
666+
};
667+
668+
BasicBlock* block;
681669

682-
if (allocator->m_HeapLocalToStackLocalMap.TryGetValue(lclNum, &newLclNum))
670+
foreach_block(comp, block)
683671
{
684-
GenTree* newTree = comp->gtNewOperNode(GT_ADDR, TYP_BYREF, comp->gtNewLclvNode(newLclNum, TYP_STRUCT));
685-
*pTree = newTree;
672+
for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
673+
{
674+
RewriteUsesVisitor rewriteUsesVisitor(this);
675+
rewriteUsesVisitor.WalkTree(&stmt->gtStmtExpr, nullptr);
676+
}
686677
}
687-
688-
return Compiler::fgWalkResult::WALK_CONTINUE;
689678
}

src/jit/objectalloc.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,7 @@ class ObjectAllocator final : public Phase
5757
GenTree* MorphAllocObjNodeIntoHelperCall(GenTreeAllocObj* allocObj);
5858
unsigned int MorphAllocObjNodeIntoStackAlloc(GenTreeAllocObj* allocObj, BasicBlock* block, GenTreeStmt* stmt);
5959
struct BuildConnGraphVisitorCallbackData;
60-
bool CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parentStack, unsigned int lclNum, Compiler* compiler);
61-
static Compiler::fgWalkResult BuildConnGraphVisitor(GenTree** pTree, Compiler::fgWalkData* data);
62-
static Compiler::fgWalkResult RewriteUsesVisitor(GenTree** pTree, Compiler::fgWalkData* data);
60+
bool CanLclVarEscapeViaParentStack(ArrayStack<GenTree*>* parentStack, unsigned int lclNum);
6361
#ifdef DEBUG
6462
static Compiler::fgWalkResult AssertWhenAllocObjFoundVisitor(GenTree** pTree, Compiler::fgWalkData* data);
6563
#endif // DEBUG
@@ -119,13 +117,15 @@ inline bool ObjectAllocator::CanAllocateLclVarOnStack(unsigned int lclNum, CORIN
119117
{
120118
assert(m_AnalysisDone);
121119

122-
if (comp->info.compCompHnd->getClassAttribs(clsHnd) & CORINFO_FLG_CONTAINS_GC_PTR)
120+
DWORD classAttribs = comp->info.compCompHnd->getClassAttribs(clsHnd);
121+
122+
if ((classAttribs & CORINFO_FLG_CONTAINS_GC_PTR) != 0)
123123
{
124124
// TODO-ObjectStackAllocation: enable stack allocation of objects with gc fields
125125
return false;
126126
}
127127

128-
if (comp->info.compCompHnd->isValueClass(clsHnd))
128+
if ((classAttribs & CORINFO_FLG_VALUECLASS) != 0)
129129
{
130130
// TODO-ObjectStackAllocation: enable stack allocation of boxed structs
131131
return false;

src/vm/jitinterface.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,6 +1961,10 @@ CEEInfo::getHeapClassSize(
19611961
MethodTable* pMT = VMClsHnd.GetMethodTable();
19621962
_ASSERTE(pMT);
19631963
_ASSERTE(!pMT->IsValueType());
1964+
_ASSERTE(!pMT->HasComponentSize());
1965+
#ifdef FEATURE_READYTORUN_COMPILER
1966+
_ASSERTE(!IsReadyToRunCompilation() || pMT->IsInheritanceChainLayoutFixedInCurrentVersionBubble());
1967+
#endif
19641968

19651969
// Add OBJECT_SIZE to account for method table pointer.
19661970
result = pMT->GetNumInstanceFieldBytes() + OBJECT_SIZE;
@@ -2283,6 +2287,11 @@ unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
22832287
_ASSERTE(sizeof(BYTE) == 1);
22842288

22852289
BOOL isValueClass = pMT->IsValueType();
2290+
2291+
#ifdef FEATURE_READYTORUN_COMPILER
2292+
_ASSERTE(isValueClass || !IsReadyToRunCompilation() || pMT->IsInheritanceChainLayoutFixedInCurrentVersionBubble());
2293+
#endif
2294+
22862295
unsigned int size = isValueClass ? VMClsHnd.GetSize() : pMT->GetNumInstanceFieldBytes() + OBJECT_SIZE;
22872296

22882297
// assume no GC pointers at first

tests/issues.targets

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,13 @@
312312
</ExcludeList>
313313
</ItemGroup>
314314

315+
<!-- x86 specific excludes -->
316+
<ItemGroup Condition="'$(XunitTestBinBase)' != '' and '$(BuildArch)' == 'x86'">
317+
<ExcludeList Include="$(XunitTestBinBase)/JIT/opt/ObjectStackAllocation/*">
318+
<Issue>Object stack allocation is not supported on x86 yet</Issue>
319+
</ExcludeList>
320+
</ItemGroup>
321+
315322
<!-- Windows arm32 specific excludes -->
316323
<ItemGroup Condition="'$(XunitTestBinBase)' != '' and '$(BuildArch)' == 'arm' and '$(TargetsWindows)' == 'true'">
317324
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NETClients/Primitives/NETClientPrimitives/*">

0 commit comments

Comments
 (0)