@@ -403,6 +403,7 @@ void EscapeAnalysis::ConnectionGraph::clear() {
403
403
UsePoints.clear ();
404
404
UsePointTable.clear ();
405
405
NodeAllocator.DestroyAll ();
406
+ valid = true ;
406
407
assert (ToMerge.empty ());
407
408
}
408
409
@@ -416,6 +417,9 @@ void EscapeAnalysis::ConnectionGraph::clear() {
416
417
// it's interior property.
417
418
EscapeAnalysis::CGNode *
418
419
EscapeAnalysis::ConnectionGraph::getNode (SILValue V) {
420
+ if (!isValid ())
421
+ return nullptr ;
422
+
419
423
// Early filter obvious non-pointer opcodes.
420
424
if (isa<FunctionRefInst>(V) || isa<DynamicFunctionRefInst>(V) ||
421
425
isa<PreviousDynamicFunctionRefInst>(V))
@@ -1028,6 +1032,9 @@ CGNode *EscapeAnalysis::ConnectionGraph::getReturnNode() {
1028
1032
1029
1033
bool EscapeAnalysis::ConnectionGraph::mergeFrom (ConnectionGraph *SourceGraph,
1030
1034
CGNodeMap &Mapping) {
1035
+ assert (isValid ());
1036
+ assert (SourceGraph->isValid ());
1037
+
1031
1038
// The main point of the merging algorithm is to map each content node in the
1032
1039
// source graph to a content node in this (destination) graph. This may
1033
1040
// require creating new nodes or merging existing nodes in this graph.
@@ -1492,6 +1499,11 @@ void EscapeAnalysis::ConnectionGraph::print(llvm::raw_ostream &OS) const {
1492
1499
#ifndef NDEBUG
1493
1500
OS << " CG of " << F->getName () << ' \n ' ;
1494
1501
1502
+ if (!isValid ()) {
1503
+ OS << " invalid\n " ;
1504
+ return ;
1505
+ }
1506
+
1495
1507
// Assign the same IDs to SILValues as the SILPrinter does.
1496
1508
llvm::DenseMap<const SILNode *, unsigned > InstToIDMap;
1497
1509
InstToIDMap[nullptr ] = (unsigned )-1 ;
@@ -1595,6 +1607,7 @@ void EscapeAnalysis::ConnectionGraph::verify() const {
1595
1607
// Invalidating EscapeAnalysis clears the connection graph.
1596
1608
if (isEmpty ())
1597
1609
return ;
1610
+ assert (isValid ());
1598
1611
1599
1612
verifyStructure ();
1600
1613
@@ -1728,10 +1741,21 @@ void EscapeAnalysis::buildConnectionGraph(FunctionInfo *FInfo,
1728
1741
// Create edges for the instructions.
1729
1742
for (auto &i : *bb) {
1730
1743
analyzeInstruction (&i, FInfo, BottomUpOrder, RecursionDepth);
1744
+
1745
+ // Bail if the graph gets too big. The node merging algorithm has
1746
+ // quadratic complexity and we want to avoid this.
1747
+ // TODO: fix the quadratic complexity (if possible) and remove this limit.
1748
+ if (ConGraph->Nodes .size () > 10000 ) {
1749
+ ConGraph->invalidate ();
1750
+ return false ;
1751
+ }
1731
1752
}
1732
1753
return true ;
1733
1754
});
1734
1755
1756
+ if (!ConGraph->isValid ())
1757
+ return ;
1758
+
1735
1759
// Second step: create defer-edges for block arguments.
1736
1760
for (SILBasicBlock &BB : *ConGraph->F ) {
1737
1761
if (!reachable.isVisited (&BB))
@@ -2478,6 +2502,16 @@ void EscapeAnalysis::recompute(FunctionInfo *Initial) {
2478
2502
bool EscapeAnalysis::mergeCalleeGraph (SILInstruction *AS,
2479
2503
ConnectionGraph *CallerGraph,
2480
2504
ConnectionGraph *CalleeGraph) {
2505
+ if (!CallerGraph->isValid ())
2506
+ return false ;
2507
+
2508
+ if (!CalleeGraph->isValid ()) {
2509
+ setAllEscaping (AS, CallerGraph);
2510
+ // Conservatively assume that setting that setAllEscaping(AS) did change the
2511
+ // graph.
2512
+ return true ;
2513
+ }
2514
+
2481
2515
// This CGNodeMap uses an intrusive worklist to keep track of Mapped nodes
2482
2516
// from the CalleeGraph. Meanwhile, mergeFrom uses separate intrusive
2483
2517
// worklists to update nodes in the CallerGraph.
@@ -2536,6 +2570,11 @@ bool EscapeAnalysis::mergeCalleeGraph(SILInstruction *AS,
2536
2570
2537
2571
bool EscapeAnalysis::mergeSummaryGraph (ConnectionGraph *SummaryGraph,
2538
2572
ConnectionGraph *Graph) {
2573
+ if (!Graph->isValid ()) {
2574
+ bool changed = SummaryGraph->isValid ();
2575
+ SummaryGraph->invalidate ();
2576
+ return changed;
2577
+ }
2539
2578
2540
2579
// Make a 1-to-1 mapping of all arguments and the return value. This CGNodeMap
2541
2580
// node map uses an intrusive worklist to keep track of Mapped nodes from the
0 commit comments