Skip to content

Commit 4158fca

Browse files
authored
JIT: revise may/must point to stack analysis (dotnet#115080)
Keep track of locals that may point to the heap as well as locals that may point to the stack. The set of definitely stack-pointing locals is then the difference in these two sets. This handles the "cyclic" case where stack pointing locals are assigned to one another. Fixes dotnet#115017
1 parent cb4581a commit 4158fca

File tree

4 files changed

+99
-16
lines changed

4 files changed

+99
-16
lines changed

src/coreclr/jit/assertionprop.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,8 @@ void Compiler::optAssertionInit(bool isLocalProp)
675675
{
676676
optMaxAssertionCount = (AssertionIndex)min(maxTrackedLocals, ((3 * lvaTrackedCount / 128) + 1) * 64);
677677
}
678+
679+
JITDUMP("Cross-block table size %u (for %u tracked locals)\n", optMaxAssertionCount, lvaTrackedCount);
678680
}
679681
else
680682
{

src/coreclr/jit/objectalloc.cpp

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ unsigned ObjectAllocator::LocalToIndex(unsigned lclNum)
133133
{
134134
unsigned result = BAD_VAR_NUM;
135135

136-
if (lclNum < comp->lvaCount)
136+
if (lclNum < m_firstPseudoLocalNum)
137137
{
138138
assert(IsTrackedLocal(lclNum));
139139
LclVarDsc* const varDsc = comp->lvaGetDesc(lclNum);
@@ -297,6 +297,7 @@ void ObjectAllocator::MarkLclVarAsEscaping(unsigned int lclNum)
297297
void ObjectAllocator::MarkLclVarAsPossiblyStackPointing(unsigned int lclNum)
298298
{
299299
const unsigned bvIndex = LocalToIndex(lclNum);
300+
JITDUMP("Marking V%02u (0x%02x) as possibly stack-pointing\n", lclNum, bvIndex);
300301
BitVecOps::AddElemD(&m_bitVecTraits, m_PossiblyStackPointingPointers, bvIndex);
301302
}
302303

@@ -839,6 +840,11 @@ void ObjectAllocator::ComputeEscapingNodes(BitVecTraits* bitVecTraits, BitVec& e
839840

840841
void ObjectAllocator::ComputeStackObjectPointers(BitVecTraits* bitVecTraits)
841842
{
843+
// Keep track of locals that we know may point at the heap
844+
//
845+
BitVec possiblyHeapPointingPointers = BitVecOps::MakeEmpty(&m_bitVecTraits);
846+
BitVecOps::AddElemD(bitVecTraits, possiblyHeapPointingPointers, m_unknownSourceIndex);
847+
842848
bool changed = true;
843849
unsigned pass = 0;
844850
while (changed)
@@ -859,23 +865,36 @@ void ObjectAllocator::ComputeStackObjectPointers(BitVecTraits* bitVecTraits)
859865
m_ConnGraphAdjacencyMatrix[lclIndex]))
860866
{
861867
// We discovered a new pointer that may point to the stack.
868+
JITDUMPEXEC(DumpIndex(lclIndex));
869+
JITDUMP(" may point to the stack\n");
862870
MarkLclVarAsPossiblyStackPointing(lclNum);
871+
changed = true;
872+
}
863873

864-
// If all locals assignable to this local are stack pointing, so is this local.
865-
//
866-
const bool isStackPointing = BitVecOps::IsSubset(bitVecTraits, m_ConnGraphAdjacencyMatrix[lclIndex],
867-
m_DefinitelyStackPointingPointers);
868-
869-
if (isStackPointing)
870-
{
871-
MarkLclVarAsDefinitelyStackPointing(lclNum);
872-
JITDUMP("V%02u is stack pointing\n", lclNum);
873-
}
874-
874+
if (!BitVecOps::IsMember(bitVecTraits, possiblyHeapPointingPointers, lclIndex) &&
875+
!BitVecOps::IsEmptyIntersection(bitVecTraits, possiblyHeapPointingPointers,
876+
m_ConnGraphAdjacencyMatrix[lclIndex]))
877+
{
878+
// We discovered a new pointer that may point to the heap.
879+
JITDUMPEXEC(DumpIndex(lclIndex));
880+
JITDUMP(" may point to the heap\n");
881+
BitVecOps::AddElemD(bitVecTraits, possiblyHeapPointingPointers, lclIndex);
875882
changed = true;
876883
}
877884
}
878885
}
886+
JITDUMP("\n---- done computing stack pointing locals\n");
887+
888+
// If a local is possibly stack pointing and not possibly heap pointing, then it is definitely stack pointing.
889+
//
890+
BitVec newDefinitelyStackPointingPointers = BitVecOps::UninitVal();
891+
BitVecOps::Assign(bitVecTraits, newDefinitelyStackPointingPointers, m_PossiblyStackPointingPointers);
892+
BitVecOps::DiffD(bitVecTraits, newDefinitelyStackPointingPointers, possiblyHeapPointingPointers);
893+
894+
// We should have only added to the set of things that are definitely stack pointing.
895+
//
896+
assert(BitVecOps::IsSubset(bitVecTraits, m_DefinitelyStackPointingPointers, newDefinitelyStackPointingPointers));
897+
BitVecOps::AssignNoCopy(bitVecTraits, m_DefinitelyStackPointingPointers, newDefinitelyStackPointingPointers);
879898

880899
#ifdef DEBUG
881900
if (comp->verbose)
@@ -1117,10 +1136,10 @@ bool ObjectAllocator::MorphAllocObjNodes()
11171136
continue;
11181137
}
11191138

1120-
bool canStack = false;
1121-
bool bashCall = false;
1122-
const char* onHeapReason = nullptr;
1123-
unsigned int lclNum = stmtExpr->AsLclVar()->GetLclNum();
1139+
bool canStack = false;
1140+
bool bashCall = false;
1141+
const char* onHeapReason = nullptr;
1142+
const unsigned int lclNum = stmtExpr->AsLclVar()->GetLclNum();
11241143

11251144
// Don't attempt to do stack allocations inside basic blocks that may be in a loop.
11261145
//
@@ -1306,6 +1325,11 @@ bool ObjectAllocator::MorphAllocObjNodes()
13061325
stmtExpr->AsLclVar()->Data() = newData;
13071326
stmtExpr->AddAllEffectsFlags(newData);
13081327
}
1328+
1329+
if (IsTrackedLocal(lclNum))
1330+
{
1331+
AddConnGraphEdge(lclNum, m_unknownSourceLocalNum);
1332+
}
13091333
}
13101334
}
13111335
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
4+
using System;
5+
using System.Runtime.CompilerServices;
6+
using Xunit;
7+
8+
public class X
9+
{
10+
public X() { a = 15; b = 35; }
11+
public int a;
12+
public int b;
13+
}
14+
15+
public class ConnectionCycles
16+
{
17+
static bool b;
18+
19+
[Fact]
20+
public static int Problem()
21+
{
22+
return SubProblem(false) + SubProblem(true);
23+
}
24+
25+
[MethodImpl(MethodImplOptions.NoInlining)]
26+
static int SubProblem(bool b)
27+
{
28+
X x1 = new X();
29+
X x2 = new X();
30+
31+
if (b)
32+
{
33+
x1 = x2;
34+
}
35+
else
36+
{
37+
x2 = x1;
38+
}
39+
40+
SideEffect();
41+
42+
return x1.a + x2.b;
43+
}
44+
45+
46+
[MethodImpl(MethodImplOptions.NoInlining)]
47+
static void SideEffect() { }
48+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<DebugType>None</DebugType>
4+
<Optimize>True</Optimize>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<Compile Include="$(MSBuildProjectName).cs" />
8+
</ItemGroup>
9+
</Project>

0 commit comments

Comments
 (0)