@@ -417,6 +417,29 @@ class CallsiteContextGraph {
417417
418418 DenseSet<uint32_t > &getContextIds () { return ContextIds; }
419419
420+ // Helper to clear the fields of this edge when we are removing it from the
421+ // graph.
422+ inline void clear () {
423+ ContextIds.clear ();
424+ AllocTypes = (uint8_t )AllocationType::None;
425+ Caller = nullptr ;
426+ Callee = nullptr ;
427+ }
428+
429+ // Check if edge was removed from the graph. This is useful while iterating
430+ // over a copy of edge lists when performing operations that mutate the
431+ // graph in ways that might remove one of the edges.
432+ inline bool isRemoved () const {
433+ if (Callee || Caller)
434+ return false ;
435+ // Any edges that have been removed from the graph but are still in a
436+ // shared_ptr somewhere should have all fields null'ed out by clear()
437+ // above.
438+ assert (AllocTypes == (uint8_t )AllocationType::None);
439+ assert (ContextIds.empty ());
440+ return true ;
441+ }
442+
420443 void dump () const ;
421444 void print (raw_ostream &OS) const ;
422445
@@ -485,6 +508,15 @@ class CallsiteContextGraph {
485508 DenseSet<uint32_t > ContextIds;
486509 };
487510
511+ // / Helper to remove edge from graph, updating edge iterator if it is provided
512+ // / (in which case CalleeIter indicates which edge list is being iterated).
513+ // / This will also perform the necessary clearing of the ContextEdge members
514+ // / to enable later checking if the edge has been removed (since we may have
515+ // / other copies of the shared_ptr in existence, and in fact rely on this to
516+ // / enable removal while iterating over a copy of a node's edge list).
517+ void removeEdgeFromGraph (ContextEdge *Edge, EdgeIter *EI = nullptr ,
518+ bool CalleeIter = true );
519+
488520 // / Assigns the given Node to calls at or inlined into the location with
489521 // / the Node's stack id, after post order traversing and processing its
490522 // / caller nodes. Uses the call information recorded in the given
@@ -920,15 +952,42 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::ContextNode::
920952 Caller->CalleeEdges .push_back (Edge);
921953}
922954
955+ template <typename DerivedCCG, typename FuncTy, typename CallTy>
956+ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::removeEdgeFromGraph(
957+ ContextEdge *Edge, EdgeIter *EI, bool CalleeIter) {
958+ assert (!EI || (*EI)->get () == Edge);
959+ // Save the Caller and Callee pointers so we can erase Edge from their edge
960+ // lists after clearing Edge below. We do the clearing first in case it is
961+ // destructed after removing from the edge lists (if those were the last
962+ // shared_ptr references to Edge).
963+ auto *Callee = Edge->Callee ;
964+ auto *Caller = Edge->Caller ;
965+
966+ // Make sure the edge fields are cleared out so we can properly detect
967+ // removed edges if Edge is not destructed because there is still a shared_ptr
968+ // reference.
969+ Edge->clear ();
970+
971+ if (!EI) {
972+ Callee->eraseCallerEdge (Edge);
973+ Caller->eraseCalleeEdge (Edge);
974+ } else if (CalleeIter) {
975+ Callee->eraseCallerEdge (Edge);
976+ *EI = Caller->CalleeEdges .erase (*EI);
977+ } else {
978+ Caller->eraseCalleeEdge (Edge);
979+ *EI = Callee->CallerEdges .erase (*EI);
980+ }
981+ }
982+
923983template <typename DerivedCCG, typename FuncTy, typename CallTy>
924984void CallsiteContextGraph<
925985 DerivedCCG, FuncTy, CallTy>::removeNoneTypeCalleeEdges(ContextNode *Node) {
926986 for (auto EI = Node->CalleeEdges .begin (); EI != Node->CalleeEdges .end ();) {
927987 auto Edge = *EI;
928988 if (Edge->AllocTypes == (uint8_t )AllocationType::None) {
929989 assert (Edge->ContextIds .empty ());
930- Edge->Callee ->eraseCallerEdge (Edge.get ());
931- EI = Node->CalleeEdges .erase (EI);
990+ removeEdgeFromGraph (Edge.get (), &EI, /* CalleeIter=*/ true );
932991 } else
933992 ++EI;
934993 }
@@ -1197,13 +1256,7 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::connectNewNode(
11971256 }
11981257 // Remove old edge if context ids empty.
11991258 if (Edge->getContextIds ().empty ()) {
1200- if (TowardsCallee) {
1201- Edge->Callee ->eraseCallerEdge (Edge.get ());
1202- EI = OrigNode->CalleeEdges .erase (EI);
1203- } else {
1204- Edge->Caller ->eraseCalleeEdge (Edge.get ());
1205- EI = OrigNode->CallerEdges .erase (EI);
1206- }
1259+ removeEdgeFromGraph (Edge.get (), &EI, TowardsCallee);
12071260 continue ;
12081261 }
12091262 ++EI;
@@ -1272,8 +1325,10 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
12721325 auto CallerEdges = Node->CallerEdges ;
12731326 for (auto &Edge : CallerEdges) {
12741327 // Skip any that have been removed during the recursion.
1275- if (!Edge)
1328+ if (Edge->isRemoved ()) {
1329+ assert (!is_contained (Node->CallerEdges , Edge));
12761330 continue ;
1331+ }
12771332 assignStackNodesPostOrder (Edge->Caller , Visited, StackIdToMatchingCalls,
12781333 CallToMatchingCall);
12791334 }
@@ -1402,10 +1457,8 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
14021457 auto *PrevEdge = CurNode->findEdgeFromCallee (PrevNode);
14031458 assert (PrevEdge);
14041459 set_subtract (PrevEdge->getContextIds (), SavedContextIds);
1405- if (PrevEdge->getContextIds ().empty ()) {
1406- PrevNode->eraseCallerEdge (PrevEdge);
1407- CurNode->eraseCalleeEdge (PrevEdge);
1408- }
1460+ if (PrevEdge->getContextIds ().empty ())
1461+ removeEdgeFromGraph (PrevEdge);
14091462 }
14101463 // Since we update the edges from leaf to tail, only look at the callee
14111464 // edges. This isn't an alloc node, so if there are no callee edges, the
@@ -2076,15 +2129,19 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::calleesMatch(
20762129 // Hook up edge's original caller to new callee node.
20772130 AddEdge (Edge->Caller , CurCalleeNode);
20782131
2132+ #ifndef NDEBUG
2133+ // Save this because Edge's fields get cleared below when removed.
2134+ auto *Caller = Edge->Caller ;
2135+ #endif
2136+
20792137 // Remove old edge
2080- Edge->Callee ->eraseCallerEdge (Edge.get ());
2081- EI = Edge->Caller ->CalleeEdges .erase (EI);
2138+ removeEdgeFromGraph (Edge.get (), &EI, /* CalleeIter=*/ true );
20822139
20832140 // To simplify the increment of EI in the caller, subtract one from EI.
20842141 // In the final AddEdge call we would have either added a new callee edge,
20852142 // to Edge->Caller, or found an existing one. Either way we are guaranteed
20862143 // that there is at least one callee edge.
2087- assert (!Edge-> Caller ->CalleeEdges .empty ());
2144+ assert (!Caller->CalleeEdges .empty ());
20882145 --EI;
20892146
20902147 return true ;
@@ -2667,30 +2724,30 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
26672724 // If we are moving all of Edge's ids, then just move the whole Edge.
26682725 // Otherwise only move the specified subset, to a new edge if needed.
26692726 if (Edge->getContextIds ().size () == ContextIdsToMove.size ()) {
2727+ // First, update the alloc types on New Callee from Edge.
2728+ // Do this before we potentially clear Edge's fields below!
2729+ NewCallee->AllocTypes |= Edge->AllocTypes ;
26702730 // Moving the whole Edge.
2671- if (CallerEdgeI)
2672- *CallerEdgeI = OldCallee->CallerEdges .erase (*CallerEdgeI);
2673- else
2674- OldCallee->eraseCallerEdge (Edge.get ());
26752731 if (ExistingEdgeToNewCallee) {
26762732 // Since we already have an edge to NewCallee, simply move the ids
26772733 // onto it, and remove the existing Edge.
26782734 ExistingEdgeToNewCallee->getContextIds ().insert (ContextIdsToMove.begin (),
26792735 ContextIdsToMove.end ());
26802736 ExistingEdgeToNewCallee->AllocTypes |= Edge->AllocTypes ;
26812737 assert (Edge->ContextIds == ContextIdsToMove);
2682- Edge->ContextIds .clear ();
2683- Edge->AllocTypes = (uint8_t )AllocationType::None;
2684- Edge->Caller ->eraseCalleeEdge (Edge.get ());
2738+ removeEdgeFromGraph (Edge.get (), CallerEdgeI, /* CalleeIter=*/ false );
26852739 } else {
26862740 // Otherwise just reconnect Edge to NewCallee.
26872741 Edge->Callee = NewCallee;
26882742 NewCallee->CallerEdges .push_back (Edge);
2743+ // Remove it from callee where it was previously connected.
2744+ if (CallerEdgeI)
2745+ *CallerEdgeI = OldCallee->CallerEdges .erase (*CallerEdgeI);
2746+ else
2747+ OldCallee->eraseCallerEdge (Edge.get ());
26892748 // Don't need to update Edge's context ids since we are simply
26902749 // reconnecting it.
26912750 }
2692- // In either case, need to update the alloc types on New Callee.
2693- NewCallee->AllocTypes |= Edge->AllocTypes ;
26942751 } else {
26952752 // Only moving a subset of Edge's ids.
26962753 if (CallerEdgeI)
@@ -2783,7 +2840,7 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::
27832840 auto CallerEdges = Node->CallerEdges ;
27842841 for (auto &Edge : CallerEdges) {
27852842 // Skip any that have been removed by an earlier recursive call.
2786- if (Edge->Callee == nullptr && Edge-> Caller == nullptr ) {
2843+ if (Edge->isRemoved () ) {
27872844 assert (!is_contained (Node->CallerEdges , Edge));
27882845 continue ;
27892846 }
@@ -2844,8 +2901,8 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
28442901 auto CallerEdges = Node->CallerEdges ;
28452902 for (auto &Edge : CallerEdges) {
28462903 // Skip any that have been removed by an earlier recursive call.
2847- if (Edge->Callee == nullptr && Edge-> Caller == nullptr ) {
2848- assert (!llvm::count (Node->CallerEdges , Edge));
2904+ if (Edge->isRemoved () ) {
2905+ assert (!is_contained (Node->CallerEdges , Edge));
28492906 continue ;
28502907 }
28512908 // Ignore any caller we previously visited via another edge.
@@ -3289,10 +3346,17 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignFunctions() {
32893346 // Reset the CallsiteToCalleeFuncCloneMap entry for any callers
32903347 // that were previously assigned to call PreviousAssignedFuncClone,
32913348 // to record that they now call NewFuncClone.
3292- for (auto CE : Clone->CallerEdges ) {
3349+ // The none type edge removal may remove some of this Clone's caller
3350+ // edges, if it is reached via another of its caller's callees.
3351+ // Iterate over a copy and skip any that were removed.
3352+ auto CallerEdges = Clone->CallerEdges ;
3353+ for (auto CE : CallerEdges) {
32933354 // Skip any that have been removed on an earlier iteration.
3294- if (!CE)
3355+ if (CE->isRemoved ()) {
3356+ assert (!is_contained (Clone->CallerEdges , CE));
32953357 continue ;
3358+ }
3359+ assert (CE);
32963360 // Ignore any caller that does not have a recorded callsite Call.
32973361 if (!CE->Caller ->hasCall ())
32983362 continue ;
@@ -3315,11 +3379,18 @@ bool CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::assignFunctions() {
33153379 // accordingly. This is important since we subsequently update the
33163380 // calls from the nodes in the graph and their assignments to callee
33173381 // functions recorded in CallsiteToCalleeFuncCloneMap.
3318- for (auto CalleeEdge : CE->Caller ->CalleeEdges ) {
3382+ // The none type edge removal may remove some of this caller's
3383+ // callee edges, if it is reached via another of its callees.
3384+ // Iterate over a copy and skip any that were removed.
3385+ auto CalleeEdges = CE->Caller ->CalleeEdges ;
3386+ for (auto CalleeEdge : CalleeEdges) {
33193387 // Skip any that have been removed on an earlier iteration when
33203388 // cleaning up newly None type callee edges.
3321- if (!CalleeEdge)
3389+ if (CalleeEdge->isRemoved ()) {
3390+ assert (!is_contained (CE->Caller ->CalleeEdges , CalleeEdge));
33223391 continue ;
3392+ }
3393+ assert (CalleeEdge);
33233394 ContextNode *Callee = CalleeEdge->Callee ;
33243395 // Skip the current callsite, we are looking for other
33253396 // callsites Caller calls, as well as any that does not have a
0 commit comments