@@ -2727,95 +2727,115 @@ bool EscapeAnalysis::canPointToSameMemory(SILValue V1, SILValue V2) {
2727
2727
return true ;
2728
2728
}
2729
2729
2730
- // Return true if deinitialization of \p releasedReference may release memory
2731
- // directly pointed to by \p accessAddress .
2730
+ // Returns true if deinitialization of \p releasedPtr may release memory
2731
+ // directly pointed to by \p livePtr .
2732
2732
//
2733
- // Note that \p accessedAddress could be a reference itself, an address of a
2734
- // local/argument that contains a reference, or even a pointer to the middle of
2735
- // an object (even if it is an exclusive argument).
2736
- //
2737
- // This is almost the same as asking "is the content node for accessedAddress
2738
- // reachable via releasedReference", with three subtle differences:
2739
- //
2740
- // (1) A locally referenced object can only be freed when deinitializing
2741
- // releasedReference if it is the same object. Indirect references will be kept
2742
- // alive by their distinct local references--ARC can't remove those without
2743
- // inserting a mark_dependence/end_dependence scope.
2744
- //
2745
- // (2) the content of exclusive arguments may be indirectly reachable via
2746
- // releasedReference, but the exclusive argument must have it's own reference
2747
- // count, so cannot be freed via the locally released reference.
2733
+ // The implementation is common between mayReleaseReferenceContent and
2734
+ // mayReleaseAddressContent, but the semantics are different. For references,
2735
+ // this models the release of the reference itself. For addresses, this models
2736
+ // the release of any reference pointed to by the address. The caller should
2737
+ // explicitly ask for the right one so they aren't surprised. Here we simply
2738
+ // switch behavior based on whether \p releasedPtr is an address type.
2748
2739
//
2749
- // (3) Objects may contain raw pointers into themselves or into other
2750
- // objects. Any access to the raw pointer is not considered a use of the object
2751
- // because that access must be "guarded" by a fix_lifetime or
2752
- // mark_dependence/end_dependence that acts as a placeholder.
2740
+ // Note that \p livePtr could be a reference itself, an address of a
2741
+ // local/argument that contains a reference, or even a pointer to the middle of
2742
+ // an object. (Even an exclusive argument may point to the middle of an object).
2753
2743
//
2754
- // There are two interesting cases in which a connection graph query can
2755
- // determine that the accessed memory cannot be released:
2744
+ // This is similar to asking "is the content of livePtr reachable via
2745
+ // releasedPtr". There are two interesting cases in which a connection graph
2746
+ // query can determine that the accessed memory cannot be released:
2756
2747
//
2757
- // Case #1: accessedAddress points to a uniquely identified object that does not
2748
+ // Case #1: \p livePtr points to a uniquely identified object that does not
2758
2749
// escape within this function.
2759
2750
//
2760
- // Note: A "uniquely identified object" is either a locally allocated object,
2761
- // which is obviously not reachable outside this function, or an exclusive
2762
- // address argument, which *is* reachable outside this function, but must
2763
- // have its own reference count so cannot be released locally.
2751
+ // In this case, it is sufficient to ensure that no connection graph path exists
2752
+ // from the content of \p livePtr to the content of \p releasedPtr.
2753
+ //
2754
+ // Note: A "uniquely identified object" is either locally allocated, which is
2755
+ // obviously not reachable outside this function, or an exclusive address, which
2756
+ // *is* reachable outside this function, but must have its own reference count
2757
+ // so cannot be released in this function or its callees.
2764
2758
//
2765
2759
// Case #2: The released reference points to a local object and no connection
2766
2760
// graph path exists from the referenced object to a global-escaping or
2767
- // argument-escaping node without traversing a non-interior edge.
2761
+ // argument-escaping node.
2762
+ //
2763
+ // TODO: This API is inneffective for release hoisting, because the release
2764
+ // itself is often the only place that an object's contents may escape. We can't
2765
+ // currently determine that since the contents cannot escape prior to \p
2766
+ // releasePtr, then livePtr cannot possible point to the same memory!
2768
2767
//
2769
- // In both cases, the connection graph is sufficient to determine if the
2770
- // accessed content may be released. To prove that the accessed memory is
2771
- // distinct from any released memory it is now sufficient to check that no
2772
- // connection graph path exists from the released object's node to the accessed
2773
- // content node without traversing a non-interior edge.
2774
- bool EscapeAnalysis::mayReleaseContent (SILValue releasedReference,
2775
- SILValue accessedAddress) {
2776
- assert (!releasedReference->getType ().isAddress ()
2777
- && " an address is never a reference" );
2778
-
2779
- SILFunction *f = getCommonFunction (releasedReference, accessedAddress);
2768
+ // TODO: In the future, we may have an AliasAnalysis query that distinguishes
2769
+ // between retain-sinking vs. release-hoisting. With SemanticARC, we may not
2770
+ // need to do this, but it is possible to be much more aggressive with
2771
+ // release-hoisting. This is becase, for a retain/release pair, it's always ok
2772
+ // to release earlier as long as there are no subsequent aliasing uses. If the
2773
+ // caller is only concerned with release hoisting and knows there are no
2774
+ // subsequent aliasing uses protected by a local release, then the connection
2775
+ // graph reachability check here only needs to search within the current object
2776
+ // (it can stop at a non-interior edge). This would assume that any indirectly
2777
+ // released reference needs to be kept alive by some distinct local
2778
+ // references--ARC can't remove those without inserting a
2779
+ // mark_dependence/end_dependence scope. It would also ignore the fact that
2780
+ // objects may contain raw pointers into themselves or into other objects. Any
2781
+ // access to the raw pointer is not considered a use of the object because that
2782
+ // access must be "guarded" by a fix_lifetime or mark_dependence/end_dependence
2783
+ // that acts as a placeholder.
2784
+ bool EscapeAnalysis::mayReleaseContent (SILValue releasedPtr, SILValue livePtr) {
2785
+ SILFunction *f = getCommonFunction (releasedPtr, livePtr);
2780
2786
if (!f)
2781
2787
return true ;
2782
2788
2783
2789
auto *conGraph = getConnectionGraph (f);
2784
2790
2785
- CGNode *addrContentNode = conGraph->getValueContent (accessedAddress );
2786
- if (!addrContentNode )
2791
+ CGNode *liveContentNode = conGraph->getValueContent (livePtr );
2792
+ if (!liveContentNode )
2787
2793
return true ;
2788
2794
2789
- // Case #1: Unique accessedAddress whose content does not escape.
2790
- bool isAccessUniq =
2791
- isUniquelyIdentified (accessedAddress)
2792
- && !addrContentNode->valueEscapesInsideFunction (accessedAddress);
2793
-
2794
- // Case #2: releasedReference points to a local object.
2795
- if (!isAccessUniq && !pointsToLocalObject (releasedReference))
2795
+ // Case #1: Unique livePtr whose content does not escape.
2796
+ //
2797
+ // If \p livePtr is an exclusive function argument, it may be indirectly
2798
+ // reachable via releasedPtr, but the exclusive argument must have it's own
2799
+ // reference count retained by the called. We consider \p livePtr unique since
2800
+ // it so cannot be freed via a release of \p releasedPtr within this function
2801
+ // or its callees.
2802
+ bool isLiveAddressUnique =
2803
+ isUniquelyIdentified (livePtr)
2804
+ && !liveContentNode->valueEscapesInsideFunction (livePtr);
2805
+
2806
+ // Case #2: releasedPtr points to a local object.
2807
+ if (!isLiveAddressUnique && !pointsToLocalObject (releasedPtr))
2796
2808
return true ;
2797
2809
2798
- CGNode *releasedObjNode = conGraph->getValueContent (releasedReference);
2810
+ // If \p releasedPtr is an address, then its released content is at least two
2811
+ // levels away: the address points to a reference, which points to an object.
2812
+ // CGNode *releasedObjNode = nullptr;
2813
+ CGNode *releasedObjNode = nullptr ;
2814
+ if (releasedPtr->getType ().isAddress ()) {
2815
+ CGNode *addrContentObjNode = conGraph->getValueContent (releasedPtr);
2816
+ if (!addrContentObjNode)
2817
+ return true ;
2818
+ releasedObjNode = conGraph->getOrCreateUnknownContent (addrContentObjNode);
2819
+ } else {
2820
+ releasedObjNode = conGraph->getValueContent (releasedPtr);
2821
+ }
2799
2822
// Make sure we have at least one value CGNode for releasedReference.
2800
2823
if (!releasedObjNode)
2801
2824
return true ;
2802
2825
2803
- // Check for reachability from releasedObjNode to addrContentNode .
2826
+ // Check for reachability from releasedObjNode to liveContentNode .
2804
2827
// A pointsTo cycle is equivalent to a null pointsTo.
2805
2828
CGNodeWorklist worklist (conGraph);
2806
2829
for (CGNode *releasedNode = releasedObjNode;
2807
2830
releasedNode && worklist.tryPush (releasedNode);
2808
2831
releasedNode = releasedNode->getContentNodeOrNull ()) {
2809
2832
// A path exists from released content to accessed content.
2810
- if (releasedNode == addrContentNode )
2833
+ if (releasedNode == liveContentNode )
2811
2834
return true ;
2812
2835
2813
2836
// A path exists to an escaping node.
2814
- if (!isAccessUniq && releasedNode->escapesInsideFunction ())
2837
+ if (!isLiveAddressUnique && releasedNode->escapesInsideFunction ())
2815
2838
return true ;
2816
-
2817
- if (!releasedNode->isInterior ())
2818
- break ;
2819
2839
}
2820
2840
return false ; // no path to escaping memory that may be freed.
2821
2841
}
0 commit comments