Skip to content

Commit 56c857a

Browse files
committed
SIL: Check for leaked instructions in the SILVerifier and in the SILModule destructor.
1 parent 61f2e7b commit 56c857a

File tree

4 files changed

+65
-2
lines changed

4 files changed

+65
-2
lines changed

include/swift/SIL/SILModule.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,19 @@ class SILModule {
650650
/// invariants.
651651
void verify() const;
652652

653+
/// Check if there are any leaking instructions.
654+
///
655+
/// Aborts with an error if more instructions are allocated than contained in
656+
/// the module.
657+
void checkForLeaks() const;
658+
659+
/// Check if there are any leaking instructions after the SILModule is
660+
/// destructed.
661+
///
662+
/// The SILModule destructor already calls checkForLeaks(). This function is
663+
/// useful to check if the destructor itself destroys all data structures.
664+
static void checkForLeaksAfterDestruction();
665+
653666
/// Pretty-print the module.
654667
void dump(bool Verbose = false) const;
655668

lib/IRGen/IRGen.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,10 @@ GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator,
10091009

10101010
// Free the memory occupied by the SILModule.
10111011
// Execute this task in parallel to the embedding of bitcode.
1012-
auto SILModuleRelease = [&SILMod]() { SILMod.reset(nullptr); };
1012+
auto SILModuleRelease = [&SILMod]() {
1013+
SILMod.reset(nullptr);
1014+
SILModule::checkForLeaksAfterDestruction();
1015+
};
10131016
auto Thread = std::thread(SILModuleRelease);
10141017
// Wait for the thread to terminate.
10151018
SWIFT_DEFER { Thread.join(); };
@@ -1307,7 +1310,10 @@ static void performParallelIRGeneration(IRGenDescriptor desc) {
13071310

13081311
// Free the memory occupied by the SILModule.
13091312
// Execute this task in parallel to the LLVM compilation.
1310-
auto SILModuleRelease = [&SILMod]() { SILMod.reset(nullptr); };
1313+
auto SILModuleRelease = [&SILMod]() {
1314+
SILMod.reset(nullptr);
1315+
SILModule::checkForLeaksAfterDestruction();
1316+
};
13111317
auto releaseModuleThread = std::thread(SILModuleRelease);
13121318

13131319
codeGenThreads.runMainThread();

lib/SIL/IR/SILModule.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ SILModule::SILModule(llvm::PointerUnion<FileUnit *, ModuleDecl *> context,
111111
}
112112

113113
SILModule::~SILModule() {
114+
#ifndef NDEBUG
115+
checkForLeaks();
116+
#endif
117+
114118
// Decrement ref count for each SILGlobalVariable with static initializers.
115119
for (SILGlobalVariable &v : silGlobals)
116120
v.dropAllReferences();
@@ -130,6 +134,44 @@ SILModule::~SILModule() {
130134
}
131135
}
132136

137+
void SILModule::checkForLeaks() const {
138+
int instsInModule = 0;
139+
for (const SILFunction &F : *this) {
140+
for (const SILBasicBlock &block : F) {
141+
instsInModule += std::distance(block.begin(), block.end());
142+
}
143+
}
144+
for (const SILFunction &F : zombieFunctions) {
145+
for (const SILBasicBlock &block : F) {
146+
instsInModule += std::distance(block.begin(), block.end());
147+
}
148+
}
149+
for (const SILGlobalVariable &global : getSILGlobals()) {
150+
instsInModule += std::distance(global.StaticInitializerBlock.begin(),
151+
global.StaticInitializerBlock.end());
152+
}
153+
154+
int numAllocated = SILInstruction::getNumCreatedInstructions() -
155+
SILInstruction::getNumDeletedInstructions();
156+
157+
if (numAllocated != instsInModule) {
158+
llvm::errs() << "Leaking instructions!\n";
159+
llvm::errs() << "Alloated instructions: " << numAllocated << '\n';
160+
llvm::errs() << "Instructions in module: " << instsInModule << '\n';
161+
llvm_unreachable("leaking instructions");
162+
}
163+
}
164+
165+
void SILModule::checkForLeaksAfterDestruction() {
166+
int numAllocated = SILInstruction::getNumCreatedInstructions() -
167+
SILInstruction::getNumDeletedInstructions();
168+
169+
if (numAllocated != 0) {
170+
llvm::errs() << "Leaking " << numAllocated << " instructions!\n";
171+
llvm_unreachable("leaking instructions");
172+
}
173+
}
174+
133175
std::unique_ptr<SILModule> SILModule::createEmptyModule(
134176
llvm::PointerUnion<FileUnit *, ModuleDecl *> context,
135177
Lowering::TypeConverter &TC, const SILOptions &Options) {

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5559,6 +5559,8 @@ void SILModule::verify() const {
55595559
if (!verificationEnabled(*this))
55605560
return;
55615561

5562+
checkForLeaks();
5563+
55625564
// Uniquing set to catch symbol name collisions.
55635565
llvm::DenseSet<StringRef> symbolNames;
55645566

0 commit comments

Comments
 (0)