Skip to content

Commit 4bda6c1

Browse files
committed
[libSyntax] Assert there are no reference-cycles in the SyntaxArenas
1 parent 96cb756 commit 4bda6c1

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

include/swift/Syntax/SyntaxArena.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "llvm/ADT/IntrusiveRefCntPtr.h"
2222
#include "llvm/ADT/SmallPtrSet.h"
2323
#include "llvm/Support/Allocator.h"
24+
#include "llvm/ADT/STLExtras.h"
25+
#include <set>
2426

2527
namespace swift {
2628
namespace syntax {
@@ -68,9 +70,26 @@ class SyntaxArena : public llvm::ThreadSafeRefCountedBase<SyntaxArena> {
6870
auto DidInsert = ChildArenas.insert(Arena);
6971
if (DidInsert.second) {
7072
Arena->Retain();
73+
assert(!Arena->containsReferenceCycle({this}));
7174
}
7275
}
7376

77+
#ifndef NDEBUG
78+
/// Check if there are any reference cycles in the child arenas. This is done
79+
/// by walking all child nodes from a root node, collecting all visited nodes
80+
/// in \p VisitedArenas. If we find a node twice, there's a reference cycle.
81+
bool
82+
containsReferenceCycle(std::set<const SyntaxArena *> VisitedArenas = {}) const {
83+
if (!VisitedArenas.insert(this).second) {
84+
// this was already in VisitedArenas -> we have a reference cycle
85+
return true;
86+
}
87+
return llvm::any_of(ChildArenas, [&](const SyntaxArena *Child) {
88+
return Child->containsReferenceCycle(VisitedArenas);
89+
});
90+
}
91+
#endif
92+
7493
void setHotUseMemoryRegion(const void *Start, const void *End) {
7594
assert(containsPointer(Start) &&
7695
"The hot use memory region should be in the Arena's bump allocator");

0 commit comments

Comments
 (0)