From: Alkis Evlogimenos Date: Sat, 14 Feb 2004 23:33:39 +0000 (+0000) Subject: Modularize implementation of LeakDetector into a typed template X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b663d76f866d03756dd563d246d9bdaabca4ca33;p=oota-llvm.git Modularize implementation of LeakDetector into a typed template implementation class. This makes the code simpler and allows for more types to be added easily. It also implements caching for generic objects (it was only available for llvm objects). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@11452 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Support/LeakDetector.cpp b/lib/Support/LeakDetector.cpp index f0cb6cc1c59..a6d96df7ba1 100644 --- a/lib/Support/LeakDetector.cpp +++ b/lib/Support/LeakDetector.cpp @@ -16,75 +16,92 @@ #include using namespace llvm; -// Lazily allocate set so that release build doesn't have to do anything. -static std::set *Objects = 0; -static std::set *LLVMObjects = 0; - -// Because the most common usage pattern, by far, is to add a garbage object, -// then remove it immediately, we optimize this case. When an object is added, -// it is not added to the set immediately, it is added to the CachedValue Value. -// If it is immediately removed, no set search need be performed. -// -static const Value *CachedValue; - -void LeakDetector::addGarbageObjectImpl(void *Object) { - if (Objects == 0) - Objects = new std::set(); - assert(Objects->count(Object) == 0 && "Object already in set!"); - Objects->insert(Object); -} +namespace { -void LeakDetector::removeGarbageObjectImpl(void *Object) { - if (Objects) - Objects->erase(Object); -} + template + struct LeakDetectorImpl { + LeakDetectorImpl(const char* const name) : Cache(0), Name(name) { } -void LeakDetector::addGarbageObjectImpl(const Value *Object) { - if (CachedValue) { - if (LLVMObjects == 0) - LLVMObjects = new std::set(); - assert(LLVMObjects->count(CachedValue) == 0 && "Object already in set!"); - LLVMObjects->insert(CachedValue); - } - CachedValue = Object; -} + // Because the most common usage pattern, by far, is to add a + // garbage object, then remove it immediately, we optimize this + // case. When an object is added, it is not added to the set + // immediately, it is added to the CachedValue Value. If it is + // immediately removed, no set search need be performed. + void addGarbage(const T* o) { + if (Cache) { + assert(Ts.count(Cache) == 0 && "Object already in set!"); + Ts.insert(Cache); + } + Cache = o; + } -void LeakDetector::removeGarbageObjectImpl(const Value *Object) { - if (Object == CachedValue) - CachedValue = 0; // Cache hit! - else if (LLVMObjects) - LLVMObjects->erase(Object); -} + void removeGarbage(const T* o) { + if (o == Cache) + Cache = 0; // Cache hit + else + Ts.erase(o); + } -void LeakDetector::checkForGarbageImpl(const std::string &Message) { - if (CachedValue) // Flush the cache to the set... - addGarbageObjectImpl((Value*)0); + bool hasGarbage(const std::string& Message) { + addGarbage(0); // Flush the Cache - assert(CachedValue == 0 && "No value should be cached anymore!"); + assert(Cache == 0 && "No value should be cached anymore!"); - if ((Objects && !Objects->empty()) || (LLVMObjects && !LLVMObjects->empty())){ - std::cerr << "Leaked objects found: " << Message << "\n"; + if (!Ts.empty()) { + std::cerr + << "Leaked " << Name << " objects found: " << Message << ":\n\t"; + std::copy(Ts.begin(), Ts.end(), + std::ostream_iterator(std::cerr, " ")); + std::cerr << '\n'; - if (Objects && !Objects->empty()) { - std::cerr << " Non-Value objects leaked:"; - for (std::set::iterator I = Objects->begin(), - E = Objects->end(); I != E; ++I) - std::cerr << " " << *I; + // Clear out results so we don't get duplicate warnings on + // next call... + Ts.clear(); + return true; + } + return false; } - if (LLVMObjects && !LLVMObjects->empty()) { - std::cerr << " LLVM Value subclasses leaked:"; - for (std::set::iterator I = LLVMObjects->begin(), - E = LLVMObjects->end(); I != E; ++I) - std::cerr << **I << "\n"; - } + private: + std::set Ts; + const T* Cache; + const char* const Name; + }; + + typedef LeakDetectorImpl Objects; + typedef LeakDetectorImpl LLVMObjects; - std::cerr << "This is probably because you removed an LLVM value " - << "(Instruction, BasicBlock, \netc), but didn't delete it. " - << "Please check your code for memory leaks.\n"; + Objects& getObjects() { + static Objects o("GENERIC"); + return o; + } - // Clear out results so we don't get duplicate warnings on next call... - delete Objects; delete LLVMObjects; - Objects = 0; LLVMObjects = 0; + LLVMObjects& getLLVMObjects() { + static LLVMObjects o("LLVM"); + return o; } } + +void LeakDetector::addGarbageObjectImpl(void *Object) { + getObjects().addGarbage(Object); +} + +void LeakDetector::addGarbageObjectImpl(const Value *Object) { + getLLVMObjects().addGarbage(Object); +} + +void LeakDetector::removeGarbageObjectImpl(void *Object) { + getObjects().removeGarbage(Object); +} + +void LeakDetector::removeGarbageObjectImpl(const Value *Object) { + getLLVMObjects().removeGarbage(Object); +} + +void LeakDetector::checkForGarbageImpl(const std::string &Message) { + // use non-short-circuit version so that both checks are performed + if (getObjects().hasGarbage(Message) | + getLLVMObjects().hasGarbage(Message)) + std::cerr << "\nThis is probably because you removed an object, but didn't " + "delete it. Please check your code for memory leaks.\n"; +} diff --git a/lib/VMCore/LeakDetector.cpp b/lib/VMCore/LeakDetector.cpp index f0cb6cc1c59..a6d96df7ba1 100644 --- a/lib/VMCore/LeakDetector.cpp +++ b/lib/VMCore/LeakDetector.cpp @@ -16,75 +16,92 @@ #include using namespace llvm; -// Lazily allocate set so that release build doesn't have to do anything. -static std::set *Objects = 0; -static std::set *LLVMObjects = 0; - -// Because the most common usage pattern, by far, is to add a garbage object, -// then remove it immediately, we optimize this case. When an object is added, -// it is not added to the set immediately, it is added to the CachedValue Value. -// If it is immediately removed, no set search need be performed. -// -static const Value *CachedValue; - -void LeakDetector::addGarbageObjectImpl(void *Object) { - if (Objects == 0) - Objects = new std::set(); - assert(Objects->count(Object) == 0 && "Object already in set!"); - Objects->insert(Object); -} +namespace { -void LeakDetector::removeGarbageObjectImpl(void *Object) { - if (Objects) - Objects->erase(Object); -} + template + struct LeakDetectorImpl { + LeakDetectorImpl(const char* const name) : Cache(0), Name(name) { } -void LeakDetector::addGarbageObjectImpl(const Value *Object) { - if (CachedValue) { - if (LLVMObjects == 0) - LLVMObjects = new std::set(); - assert(LLVMObjects->count(CachedValue) == 0 && "Object already in set!"); - LLVMObjects->insert(CachedValue); - } - CachedValue = Object; -} + // Because the most common usage pattern, by far, is to add a + // garbage object, then remove it immediately, we optimize this + // case. When an object is added, it is not added to the set + // immediately, it is added to the CachedValue Value. If it is + // immediately removed, no set search need be performed. + void addGarbage(const T* o) { + if (Cache) { + assert(Ts.count(Cache) == 0 && "Object already in set!"); + Ts.insert(Cache); + } + Cache = o; + } -void LeakDetector::removeGarbageObjectImpl(const Value *Object) { - if (Object == CachedValue) - CachedValue = 0; // Cache hit! - else if (LLVMObjects) - LLVMObjects->erase(Object); -} + void removeGarbage(const T* o) { + if (o == Cache) + Cache = 0; // Cache hit + else + Ts.erase(o); + } -void LeakDetector::checkForGarbageImpl(const std::string &Message) { - if (CachedValue) // Flush the cache to the set... - addGarbageObjectImpl((Value*)0); + bool hasGarbage(const std::string& Message) { + addGarbage(0); // Flush the Cache - assert(CachedValue == 0 && "No value should be cached anymore!"); + assert(Cache == 0 && "No value should be cached anymore!"); - if ((Objects && !Objects->empty()) || (LLVMObjects && !LLVMObjects->empty())){ - std::cerr << "Leaked objects found: " << Message << "\n"; + if (!Ts.empty()) { + std::cerr + << "Leaked " << Name << " objects found: " << Message << ":\n\t"; + std::copy(Ts.begin(), Ts.end(), + std::ostream_iterator(std::cerr, " ")); + std::cerr << '\n'; - if (Objects && !Objects->empty()) { - std::cerr << " Non-Value objects leaked:"; - for (std::set::iterator I = Objects->begin(), - E = Objects->end(); I != E; ++I) - std::cerr << " " << *I; + // Clear out results so we don't get duplicate warnings on + // next call... + Ts.clear(); + return true; + } + return false; } - if (LLVMObjects && !LLVMObjects->empty()) { - std::cerr << " LLVM Value subclasses leaked:"; - for (std::set::iterator I = LLVMObjects->begin(), - E = LLVMObjects->end(); I != E; ++I) - std::cerr << **I << "\n"; - } + private: + std::set Ts; + const T* Cache; + const char* const Name; + }; + + typedef LeakDetectorImpl Objects; + typedef LeakDetectorImpl LLVMObjects; - std::cerr << "This is probably because you removed an LLVM value " - << "(Instruction, BasicBlock, \netc), but didn't delete it. " - << "Please check your code for memory leaks.\n"; + Objects& getObjects() { + static Objects o("GENERIC"); + return o; + } - // Clear out results so we don't get duplicate warnings on next call... - delete Objects; delete LLVMObjects; - Objects = 0; LLVMObjects = 0; + LLVMObjects& getLLVMObjects() { + static LLVMObjects o("LLVM"); + return o; } } + +void LeakDetector::addGarbageObjectImpl(void *Object) { + getObjects().addGarbage(Object); +} + +void LeakDetector::addGarbageObjectImpl(const Value *Object) { + getLLVMObjects().addGarbage(Object); +} + +void LeakDetector::removeGarbageObjectImpl(void *Object) { + getObjects().removeGarbage(Object); +} + +void LeakDetector::removeGarbageObjectImpl(const Value *Object) { + getLLVMObjects().removeGarbage(Object); +} + +void LeakDetector::checkForGarbageImpl(const std::string &Message) { + // use non-short-circuit version so that both checks are performed + if (getObjects().hasGarbage(Message) | + getLLVMObjects().hasGarbage(Message)) + std::cerr << "\nThis is probably because you removed an object, but didn't " + "delete it. Please check your code for memory leaks.\n"; +}