@@ -72,7 +72,8 @@ EscapeAnalysis::findRecursivePointerKind(SILType Ty,
72
72
};
73
73
if (auto *Str = Ty.getStructOrBoundGenericStruct ()) {
74
74
for (auto *Field : Str->getStoredProperties ()) {
75
- SILType fieldTy = Ty.getFieldType (Field, M, F.getTypeExpansionContext ());
75
+ SILType fieldTy = Ty.getFieldType (Field, M, F.getTypeExpansionContext ())
76
+ .getObjectType ();
76
77
meetAggregateKind (findCachedPointerKind (fieldTy, F));
77
78
}
78
79
return aggregateKind;
@@ -925,8 +926,10 @@ EscapeAnalysis::ConnectionGraph::getOrCreateReferenceContent(SILValue refVal,
925
926
if (auto *C = refType.getClassOrBoundGenericClass ()) {
926
927
PointerKind aggregateKind = NoPointer;
927
928
for (auto *field : C->getStoredProperties ()) {
928
- SILType fieldType = refType.getFieldType (field, F->getModule (),
929
- F->getTypeExpansionContext ());
929
+ SILType fieldType = refType
930
+ .getFieldType (field, F->getModule (),
931
+ F->getTypeExpansionContext ())
932
+ .getObjectType ();
930
933
PointerKind fieldKind = EA->findCachedPointerKind (fieldType, *F);
931
934
if (fieldKind > aggregateKind)
932
935
aggregateKind = fieldKind;
@@ -1161,19 +1164,6 @@ bool EscapeAnalysis::ConnectionGraph::forwardTraverseDefer(
1161
1164
return true ;
1162
1165
}
1163
1166
1164
- bool EscapeAnalysis::ConnectionGraph::mayReach (CGNode *pointer,
1165
- CGNode *pointee) {
1166
- if (pointer == pointee)
1167
- return true ;
1168
-
1169
- // This query is successful when the traversal halts and returns false.
1170
- return !backwardTraverse (pointee, [pointer](Predecessor pred) {
1171
- if (pred.getPredNode () == pointer)
1172
- return Traversal::Halt;
1173
- return Traversal::Follow;
1174
- });
1175
- }
1176
-
1177
1167
void EscapeAnalysis::ConnectionGraph::removeFromGraph (ValueBase *V) {
1178
1168
CGNode *node = Values2Nodes.lookup (V);
1179
1169
if (!node)
@@ -1193,10 +1183,7 @@ void EscapeAnalysis::ConnectionGraph::removeFromGraph(ValueBase *V) {
1193
1183
// / This makes iterating over the edges easier.
1194
1184
struct CGForDotView {
1195
1185
1196
- enum EdgeTypes {
1197
- PointsTo,
1198
- Deferred
1199
- };
1186
+ enum EdgeTypes { PointsTo, Reference, Deferred };
1200
1187
1201
1188
struct Node {
1202
1189
EscapeAnalysis::CGNode *OrigNode;
@@ -1248,7 +1235,10 @@ CGForDotView::CGForDotView(const EscapeAnalysis::ConnectionGraph *CG) :
1248
1235
Nd.OrigNode = OrigNode;
1249
1236
if (auto *PT = OrigNode->getPointsToEdge ()) {
1250
1237
Nd.Children .push_back (Orig2Node[PT]);
1251
- Nd.ChildrenTypes .push_back (PointsTo);
1238
+ if (OrigNode->hasReferenceOnly ())
1239
+ Nd.ChildrenTypes .push_back (Reference);
1240
+ else
1241
+ Nd.ChildrenTypes .push_back (PointsTo);
1252
1242
}
1253
1243
for (auto *Def : OrigNode->defersTo ) {
1254
1244
Nd.Children .push_back (Orig2Node[Def]);
@@ -1396,8 +1386,12 @@ namespace llvm {
1396
1386
const CGForDotView *Graph) {
1397
1387
unsigned ChildIdx = I - Node->Children .begin ();
1398
1388
switch (Node->ChildrenTypes [ChildIdx]) {
1399
- case CGForDotView::PointsTo: return " " ;
1400
- case CGForDotView::Deferred: return " color=\" gray\" " ;
1389
+ case CGForDotView::PointsTo:
1390
+ return " " ;
1391
+ case CGForDotView::Reference:
1392
+ return " color=\" green\" " ;
1393
+ case CGForDotView::Deferred:
1394
+ return " color=\" gray\" " ;
1401
1395
}
1402
1396
1403
1397
llvm_unreachable (" Unhandled CGForDotView in switch." );
@@ -2570,24 +2564,6 @@ static SILFunction *getCommonFunction(SILValue V1, SILValue V2) {
2570
2564
return F;
2571
2565
}
2572
2566
2573
- bool EscapeAnalysis::canEscapeToValue (SILValue V, SILValue To) {
2574
- if (!isUniquelyIdentified (V))
2575
- return true ;
2576
-
2577
- SILFunction *F = getCommonFunction (V, To);
2578
- if (!F)
2579
- return true ;
2580
- auto *ConGraph = getConnectionGraph (F);
2581
-
2582
- CGNode *valueContent = ConGraph->getValueContent (V);
2583
- if (!valueContent)
2584
- return true ;
2585
- CGNode *userContent = ConGraph->getValueContent (To);
2586
- if (!userContent)
2587
- return true ;
2588
- return ConGraph->mayReach (userContent, valueContent);
2589
- }
2590
-
2591
2567
bool EscapeAnalysis::canPointToSameMemory (SILValue V1, SILValue V2) {
2592
2568
// At least one of the values must be a non-escaping local object.
2593
2569
bool isUniq1 = isUniquelyIdentified (V1);
@@ -2642,6 +2618,99 @@ bool EscapeAnalysis::canPointToSameMemory(SILValue V1, SILValue V2) {
2642
2618
return true ;
2643
2619
}
2644
2620
2621
+ // Return true if deinitialization of \p releasedReference may release memory
2622
+ // directly pointed to by \p accessAddress.
2623
+ //
2624
+ // Note that \p accessedAddress could be a reference itself, an address of a
2625
+ // local/argument that contains a reference, or even a pointer to the middle of
2626
+ // an object (even if it is an exclusive argument).
2627
+ //
2628
+ // This is almost the same as asking "is the content node for accessedAddress
2629
+ // reachable via releasedReference", with three subtle differences:
2630
+ //
2631
+ // (1) A locally referenced object can only be freed when deinitializing
2632
+ // releasedReference if it is the same object. Indirect references will be kept
2633
+ // alive by their distinct local references--ARC can't remove those without
2634
+ // inserting a mark_dependence/end_dependence scope.
2635
+ //
2636
+ // (2) the content of exclusive arguments may be indirectly reachable via
2637
+ // releasedReference, but the exclusive argument must have it's own reference
2638
+ // count, so cannot be freed via the locally released reference.
2639
+ //
2640
+ // (3) Objects may contain raw pointers into themselves or into other
2641
+ // objects. Any access to the raw pointer is not considered a use of the object
2642
+ // because that access must be "guarded" by a fix_lifetime or
2643
+ // mark_dependence/end_dependence that acts as a placeholder.
2644
+ //
2645
+ // There are two interesting cases in which a connection graph query can
2646
+ // determine that the accessed memory cannot be released:
2647
+ //
2648
+ // Case #1: accessedAddress points to a uniquely identified object that does not
2649
+ // escape within this function.
2650
+ //
2651
+ // Note: A "uniquely identified object" is either a locally allocated object,
2652
+ // which is obviously not reachable outside this function, or an exclusive
2653
+ // address argument, which *is* reachable outside this function, but must
2654
+ // have its own reference count so cannot be released locally.
2655
+ //
2656
+ // Case #2: The released reference points to a local object and no connection
2657
+ // graph path exists from the referenced object to a global-escaping or
2658
+ // argument-escaping node without traversing a non-interior edge.
2659
+ //
2660
+ // In both cases, the connection graph is sufficient to determine if the
2661
+ // accessed content may be released. To prove that the accessed memory is
2662
+ // distinct from any released memory it is now sufficient to check that no
2663
+ // connection graph path exists from the released object's node to the accessed
2664
+ // content node without traversing a non-interior edge.
2665
+ bool EscapeAnalysis::mayReleaseContent (SILValue releasedReference,
2666
+ SILValue accessedAddress) {
2667
+ assert (!releasedReference->getType ().isAddress ()
2668
+ && " an address is never a reference" );
2669
+
2670
+ SILFunction *f = getCommonFunction (releasedReference, accessedAddress);
2671
+ if (!f)
2672
+ return true ;
2673
+
2674
+ auto *conGraph = getConnectionGraph (f);
2675
+
2676
+ CGNode *addrContentNode = conGraph->getValueContent (accessedAddress);
2677
+ if (!addrContentNode)
2678
+ return true ;
2679
+
2680
+ // Case #1: Unique accessedAddress whose content does not escape.
2681
+ bool isAccessUniq =
2682
+ isUniquelyIdentified (accessedAddress)
2683
+ && !addrContentNode->valueEscapesInsideFunction (accessedAddress);
2684
+
2685
+ // Case #2: releasedReference points to a local object.
2686
+ if (!isAccessUniq && !pointsToLocalObject (releasedReference))
2687
+ return true ;
2688
+
2689
+ CGNode *releasedObjNode = conGraph->getValueContent (releasedReference);
2690
+ // Make sure we have at least one value CGNode for releasedReference.
2691
+ if (!releasedObjNode)
2692
+ return true ;
2693
+
2694
+ // Check for reachability from releasedObjNode to addrContentNode.
2695
+ // A pointsTo cycle is equivalent to a null pointsTo.
2696
+ CGNodeWorklist worklist (conGraph);
2697
+ for (CGNode *releasedNode = releasedObjNode;
2698
+ releasedNode && worklist.tryPush (releasedNode);
2699
+ releasedNode = releasedNode->getContentNodeOrNull ()) {
2700
+ // A path exists from released content to accessed content.
2701
+ if (releasedNode == addrContentNode)
2702
+ return true ;
2703
+
2704
+ // A path exists to an escaping node.
2705
+ if (!isAccessUniq && releasedNode->escapesInsideFunction ())
2706
+ return true ;
2707
+
2708
+ if (!releasedNode->isInterior ())
2709
+ break ;
2710
+ }
2711
+ return false ; // no path to escaping memory that may be freed.
2712
+ }
2713
+
2645
2714
void EscapeAnalysis::invalidate () {
2646
2715
Function2Info.clear ();
2647
2716
Allocator.DestroyAll ();
0 commit comments