mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-26 21:47:07 +00:00
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). llvm-svn: 11452
This commit is contained in:
parent
cc5bf36481
commit
0a88b596b1
@ -16,75 +16,92 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
// Lazily allocate set so that release build doesn't have to do anything.
|
namespace {
|
||||||
static std::set<const void*> *Objects = 0;
|
|
||||||
static std::set<const Value*> *LLVMObjects = 0;
|
|
||||||
|
|
||||||
// Because the most common usage pattern, by far, is to add a garbage object,
|
template <typename T>
|
||||||
// then remove it immediately, we optimize this case. When an object is added,
|
struct LeakDetectorImpl {
|
||||||
// it is not added to the set immediately, it is added to the CachedValue Value.
|
LeakDetectorImpl(const char* const name) : Cache(0), Name(name) { }
|
||||||
// If it is immediately removed, no set search need be performed.
|
|
||||||
//
|
|
||||||
static const Value *CachedValue;
|
|
||||||
|
|
||||||
void LeakDetector::addGarbageObjectImpl(void *Object) {
|
// Because the most common usage pattern, by far, is to add a
|
||||||
if (Objects == 0)
|
// garbage object, then remove it immediately, we optimize this
|
||||||
Objects = new std::set<const void*>();
|
// case. When an object is added, it is not added to the set
|
||||||
assert(Objects->count(Object) == 0 && "Object already in set!");
|
// immediately, it is added to the CachedValue Value. If it is
|
||||||
Objects->insert(Object);
|
// 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(void *Object) {
|
void removeGarbage(const T* o) {
|
||||||
if (Objects)
|
if (o == Cache)
|
||||||
Objects->erase(Object);
|
Cache = 0; // Cache hit
|
||||||
|
else
|
||||||
|
Ts.erase(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasGarbage(const std::string& Message) {
|
||||||
|
addGarbage(0); // Flush the Cache
|
||||||
|
|
||||||
|
assert(Cache == 0 && "No value should be cached anymore!");
|
||||||
|
|
||||||
|
if (!Ts.empty()) {
|
||||||
|
std::cerr
|
||||||
|
<< "Leaked " << Name << " objects found: " << Message << ":\n\t";
|
||||||
|
std::copy(Ts.begin(), Ts.end(),
|
||||||
|
std::ostream_iterator<const T*>(std::cerr, " "));
|
||||||
|
std::cerr << '\n';
|
||||||
|
|
||||||
|
// Clear out results so we don't get duplicate warnings on
|
||||||
|
// next call...
|
||||||
|
Ts.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::set<const T*> Ts;
|
||||||
|
const T* Cache;
|
||||||
|
const char* const Name;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef LeakDetectorImpl<void> Objects;
|
||||||
|
typedef LeakDetectorImpl<Value> LLVMObjects;
|
||||||
|
|
||||||
|
Objects& getObjects() {
|
||||||
|
static Objects o("GENERIC");
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVMObjects& getLLVMObjects() {
|
||||||
|
static LLVMObjects o("LLVM");
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LeakDetector::addGarbageObjectImpl(void *Object) {
|
||||||
|
getObjects().addGarbage(Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeakDetector::addGarbageObjectImpl(const Value *Object) {
|
void LeakDetector::addGarbageObjectImpl(const Value *Object) {
|
||||||
if (CachedValue) {
|
getLLVMObjects().addGarbage(Object);
|
||||||
if (LLVMObjects == 0)
|
|
||||||
LLVMObjects = new std::set<const Value*>();
|
|
||||||
assert(LLVMObjects->count(CachedValue) == 0 && "Object already in set!");
|
|
||||||
LLVMObjects->insert(CachedValue);
|
|
||||||
}
|
}
|
||||||
CachedValue = Object;
|
|
||||||
|
void LeakDetector::removeGarbageObjectImpl(void *Object) {
|
||||||
|
getObjects().removeGarbage(Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeakDetector::removeGarbageObjectImpl(const Value *Object) {
|
void LeakDetector::removeGarbageObjectImpl(const Value *Object) {
|
||||||
if (Object == CachedValue)
|
getLLVMObjects().removeGarbage(Object);
|
||||||
CachedValue = 0; // Cache hit!
|
|
||||||
else if (LLVMObjects)
|
|
||||||
LLVMObjects->erase(Object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeakDetector::checkForGarbageImpl(const std::string &Message) {
|
void LeakDetector::checkForGarbageImpl(const std::string &Message) {
|
||||||
if (CachedValue) // Flush the cache to the set...
|
// use non-short-circuit version so that both checks are performed
|
||||||
addGarbageObjectImpl((Value*)0);
|
if (getObjects().hasGarbage(Message) |
|
||||||
|
getLLVMObjects().hasGarbage(Message))
|
||||||
assert(CachedValue == 0 && "No value should be cached anymore!");
|
std::cerr << "\nThis is probably because you removed an object, but didn't "
|
||||||
|
"delete it. Please check your code for memory leaks.\n";
|
||||||
if ((Objects && !Objects->empty()) || (LLVMObjects && !LLVMObjects->empty())){
|
|
||||||
std::cerr << "Leaked objects found: " << Message << "\n";
|
|
||||||
|
|
||||||
if (Objects && !Objects->empty()) {
|
|
||||||
std::cerr << " Non-Value objects leaked:";
|
|
||||||
for (std::set<const void*>::iterator I = Objects->begin(),
|
|
||||||
E = Objects->end(); I != E; ++I)
|
|
||||||
std::cerr << " " << *I;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LLVMObjects && !LLVMObjects->empty()) {
|
|
||||||
std::cerr << " LLVM Value subclasses leaked:";
|
|
||||||
for (std::set<const Value*>::iterator I = LLVMObjects->begin(),
|
|
||||||
E = LLVMObjects->end(); I != E; ++I)
|
|
||||||
std::cerr << **I << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
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";
|
|
||||||
|
|
||||||
// Clear out results so we don't get duplicate warnings on next call...
|
|
||||||
delete Objects; delete LLVMObjects;
|
|
||||||
Objects = 0; LLVMObjects = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user