@@ -51,6 +51,7 @@ ObjectAllocator::ObjectAllocator(Compiler* comp)
5151 , m_maxPseudos(0 )
5252 , m_regionsToClone(0 )
5353 , m_trackFields(false )
54+ , m_StoreAddressToIndexMap(comp->getAllocator (CMK_ObjectAllocator))
5455{
5556 m_EscapingPointers = BitVecOps::UninitVal ();
5657 m_PossiblyStackPointingPointers = BitVecOps::UninitVal ();
@@ -564,6 +565,34 @@ void ObjectAllocator::DoAnalysis()
564565 ComputeEscapingNodes (&m_bitVecTraits, m_EscapingPointers);
565566 }
566567
568+ #ifdef DEBUG
569+ // Print the connection graph
570+ //
571+ if (JitConfig.JitObjectStackAllocationDumpConnGraph () > 0 )
572+ {
573+ JITDUMP (" digraph ConnectionGraph {\n " );
574+ for (unsigned int i = 0 ; i < m_bvCount; i++)
575+ {
576+ BitVecOps::Iter iterator (&m_bitVecTraits, m_ConnGraphAdjacencyMatrix[i]);
577+ unsigned int lclIndex;
578+ while (iterator.NextElem (&lclIndex))
579+ {
580+ JITDUMPEXEC (DumpIndex (lclIndex));
581+ JITDUMP (" -> " );
582+ JITDUMPEXEC (DumpIndex (i));
583+ JITDUMP (" ;\n " );
584+ }
585+
586+ if (CanIndexEscape (i))
587+ {
588+ JITDUMPEXEC (DumpIndex (i));
589+ JITDUMP (" -> E;\n " );
590+ }
591+ }
592+ JITDUMP (" }\n " );
593+ }
594+ #endif
595+
567596 m_AnalysisDone = true ;
568597}
569598
@@ -1731,6 +1760,7 @@ void ObjectAllocator::AnalyzeParentStack(ArrayStack<GenTree*>* parentStack, unsi
17311760 }
17321761
17331762 // Check whether the local escapes higher up
1763+ isAddress = false ;
17341764 ++parentIndex;
17351765 keepChecking = true ;
17361766 break ;
@@ -1755,58 +1785,49 @@ void ObjectAllocator::AnalyzeParentStack(ArrayStack<GenTree*>* parentStack, unsi
17551785
17561786 case GT_STOREIND:
17571787 case GT_STORE_BLK:
1758- case GT_BLK:
17591788 {
17601789 GenTree* const addr = parent->AsIndir ()->Addr ();
17611790 if (tree == addr)
17621791 {
1763- JITDUMP (" ... store address\n " );
1792+ if (isAddress)
1793+ {
1794+ // Remember the resource being stored to.
1795+ //
1796+ JITDUMP (" ... store address\n " );
1797+ m_StoreAddressToIndexMap.Set (tree, lclIndex);
1798+ }
1799+
1800+ // The address does not escape
1801+ //
17641802 canLclVarEscapeViaParentStack = false ;
17651803 break ;
17661804 }
17671805
1768- // If the value being stored is a local address, anything assigned to that local escapes
1806+ // Is this a store to a tracked resource?
17691807 //
1770- if (isAddress)
1808+ unsigned dstIndex;
1809+ if (m_trackFields && m_StoreAddressToIndexMap.Lookup (addr, &dstIndex) && (dstIndex != BAD_VAR_NUM))
17711810 {
1772- break ;
1773- }
1811+ JITDUMP (" ... local.field store\n " );
17741812
1775- // Is this a store to a field of a local struct...?
1776- //
1777- if (parent->OperIs (GT_STOREIND))
1778- {
1779- // Are we storing to a local field?
1780- //
1781- if (addr->OperIs (GT_FIELD_ADDR))
1813+ if (!isAddress)
17821814 {
1783- // Simple check for which local.
1784- //
1785- GenTree* const base = addr->AsOp ()->gtGetOp1 ();
1786-
1787- if (base->OperIs (GT_LCL_ADDR))
1788- {
1789- unsigned const dstLclNum = base->AsLclVarCommon ()->GetLclNum ();
1790-
1791- if (IsTrackedLocal (dstLclNum))
1792- {
1793- JITDUMP (" ... local.field store\n " );
1794- const unsigned dstIndex = LocalToIndex (dstLclNum);
1795- // Add an edge to the connection graph.
1796- //
1797- AddConnGraphEdgeIndex (dstIndex, lclIndex);
1798- canLclVarEscapeViaParentStack = false ;
1799- }
1800- }
1815+ AddConnGraphEdgeIndex (dstIndex, lclIndex);
1816+ canLclVarEscapeViaParentStack = false ;
1817+ break ;
1818+ }
1819+ else
1820+ {
1821+ AddConnGraphEdgeIndex (dstIndex, m_unknownSourceIndex);
18011822 }
1802-
1803- // Else we're storing the value somewhere unknown.
1804- // Assume the worst.
18051823 }
1824+
1825+ // We're storing the value somewhere unknown. Assume the worst.
18061826 break ;
18071827 }
18081828
18091829 case GT_IND:
1830+ case GT_BLK:
18101831 {
18111832 // Does this load a type we're tracking?
18121833 //
@@ -1820,12 +1841,12 @@ void ObjectAllocator::AnalyzeParentStack(ArrayStack<GenTree*>* parentStack, unsi
18201841
18211842 // For loads from local structs we may be tracking the underlying fields.
18221843 //
1823- // We can assume that the local being read is lclNum, since we have walked up to this node from a leaf
1824- // local.
1844+ // We can assume that the local being read is lclNum,
1845+ // since we have walked up to this node from a leaf local.
18251846 //
18261847 // We only track through the first indir.
18271848 //
1828- if (m_trackFields && isAddress && addr-> OperIs (GT_FIELD_ADDR) )
1849+ if (m_trackFields && isAddress)
18291850 {
18301851 JITDUMP (" ... load local.field\n " );
18311852 ++parentIndex;
@@ -2076,7 +2097,6 @@ void ObjectAllocator::UpdateAncestorTypes(GenTree* tree,
20762097
20772098 case GT_STOREIND:
20782099 case GT_STORE_BLK:
2079- case GT_BLK:
20802100 {
20812101 if (tree == parent->AsIndir ()->Addr ())
20822102 {
@@ -2107,10 +2127,11 @@ void ObjectAllocator::UpdateAncestorTypes(GenTree* tree,
21072127 }
21082128
21092129 case GT_IND:
2130+ case GT_BLK:
21102131 {
21112132 // If we are loading from a GC struct field, we may need to retype the load
21122133 //
2113- if (retypeFields && (tree-> OperIs (GT_FIELD_ADDR)) && ( varTypeIsGC (parent->TypeGet ())))
2134+ if (retypeFields && (varTypeIsGC (parent->TypeGet ())))
21142135 {
21152136 parent->ChangeType (newType);
21162137 ++parentIndex;
0 commit comments