Index: include/core/SkInstCnt.h |
diff --git a/include/core/SkInstCnt.h b/include/core/SkInstCnt.h |
index e4b43d130b94b6a2ab9303c3c6c1170f7c3722ff..8aeb14ec1a818f0845c22f13e667740437e5c955 100644 |
--- a/include/core/SkInstCnt.h |
+++ b/include/core/SkInstCnt.h |
@@ -5,143 +5,76 @@ |
* found in the LICENSE file. |
*/ |
- |
#ifndef SkInstCnt_DEFINED |
#define SkInstCnt_DEFINED |
-/* |
- * The instance counting system consists of three macros that create the |
- * instance counting machinery. A class is added to the system by adding: |
- * SK_DECLARE_INST_COUNT at the top of its declaration for derived classes |
- * SK_DECLARE_INST_COUNT_ROOT at the top of its declaration for a root class |
- * At the end of an application a call to all the "root" objects' |
- * CheckInstanceCount methods should be made |
+/* To count all instances of T, including all subclasses of T, |
+ * add SK_DECLARE_INST_COUNT(T) to T's class definition. |
+ * If you want to print out counts of leaked instances, set gPrintInstCount to true in main(). |
+ * |
+ * E.g. |
+ * struct Base { SK_DECLARE_INST_COUNT(Base) }; |
+ * struct A : public Base {}; |
+ * struct SubBase : public Base { SK_DECLARE_INST_COUNT(SubBase); } |
+ * struct B : public SubBase {}; |
+ * |
+ * If gPrintInstCount is true, at the program exit you will see something like: |
+ * Base: <N> leaked instances |
+ * SubBase: <M> leaked instances |
+ * where N >= M. Leaked instances of A count against Base; leaked instances of B count against |
+ * both SubBase and Base. |
+ * |
+ * If SK_ENABLE_INST_COUNT is not defined or defined to 0, or we're in a shared library build, |
+ * this entire system is compiled away to a noop. |
*/ |
+ |
#include "SkTypes.h" |
-#if SK_ENABLE_INST_COUNT |
-// Static variables inside member functions below may be defined multiple times |
-// if Skia is being used as a dynamic library. Instance counting should be on |
-// only for static builds. See bug skia:2058. |
-#if defined(SKIA_DLL) |
-#error Instance counting works only when Skia is built as a static library. |
-#endif |
+#if SK_ENABLE_INST_COUNT && !defined(SKIA_DLL) // See skia:2058 for why we noop on shared builds. |
+ #include "SkThread.h" |
+ #include <stdlib.h> |
+ |
+ #define SK_DECLARE_INST_COUNT(T) \ |
+ static const char* InstCountClassName() { return #T; } \ |
+ SkInstCount<T, T::InstCountClassName> fInstCnt; \ |
+ static int32_t GetInstanceCount() { return SkInstCount<T, InstCountClassName>::Count(); } |
+ |
+ extern bool gPrintInstCount; |
-#include "SkOnce.h" |
-#include "SkTArray.h" |
-#include "SkThread.h" |
-extern bool gPrintInstCount; |
+ template <typename T, const char*(Name)()> |
+ class SkInstCount { |
+ public: |
+ SkInstCount() { Inc(); } |
+ SkInstCount(const SkInstCount&) { Inc(); } |
+ ~SkInstCount() { sk_atomic_dec(&gCount); } |
-// The non-root classes just register themselves with their parent |
-#define SK_DECLARE_INST_COUNT(className) \ |
- SK_DECLARE_INST_COUNT_INTERNAL(className, \ |
- INHERITED::AddInstChild(CheckInstanceCount);) |
+ SkInstCount& operator==(const SkInstCount&) { return *this; } // == can't change the count. |
-// The root classes registers a function to print out the memory stats when |
-// the app ends |
-#define SK_DECLARE_INST_COUNT_ROOT(className) \ |
- SK_DECLARE_INST_COUNT_INTERNAL(className, atexit(exitPrint);) |
+ static void Inc() { |
+ // If it's the first time we go from 0 to 1, register to print leaks at process exit. |
+ if (0 == sk_atomic_inc(&gCount) && sk_atomic_cas(&gRegistered, 0, 1)) { |
+ atexit(PrintAtExit); |
+ } |
+ } |
-#define SK_DECLARE_INST_COUNT_INTERNAL(className, initStep) \ |
- class SkInstanceCountHelper { \ |
- public: \ |
- SkInstanceCountHelper() { \ |
- SK_DECLARE_STATIC_ONCE(once); \ |
- SkOnce(&once, init); \ |
- sk_atomic_inc(GetInstanceCountPtr()); \ |
- } \ |
- \ |
- static void init() { \ |
- initStep \ |
- } \ |
- \ |
- SkInstanceCountHelper(const SkInstanceCountHelper&) { \ |
- sk_atomic_inc(GetInstanceCountPtr()); \ |
- } \ |
- \ |
- ~SkInstanceCountHelper() { \ |
- sk_atomic_dec(GetInstanceCountPtr()); \ |
- } \ |
- \ |
- static int32_t* GetInstanceCountPtr() { \ |
- static int32_t gInstanceCount; \ |
- return &gInstanceCount; \ |
- } \ |
- \ |
- static SkTArray<int (*)(int, bool)>*& GetChildren() { \ |
- static SkTArray<int (*)(int, bool)>* gChildren; \ |
- return gChildren; \ |
- } \ |
- \ |
- static void create_mutex(SkMutex** mutex) { \ |
- *mutex = SkNEW(SkMutex); \ |
- } \ |
- static SkBaseMutex& GetChildrenMutex() { \ |
- static SkMutex* childrenMutex; \ |
- SK_DECLARE_STATIC_ONCE(once); \ |
- SkOnce(&once, className::SkInstanceCountHelper::create_mutex, &childrenMutex);\ |
- return *childrenMutex; \ |
- } \ |
- \ |
- } fInstanceCountHelper; \ |
- \ |
- static int32_t GetInstanceCount() { \ |
- return *SkInstanceCountHelper::GetInstanceCountPtr(); \ |
- } \ |
- \ |
- static void exitPrint() { \ |
- CheckInstanceCount(0, true); \ |
- } \ |
- \ |
- static int CheckInstanceCount(int level = 0, bool cleanUp = false) { \ |
- if (gPrintInstCount && 0 != GetInstanceCount()) { \ |
- SkDebugf("%*c Leaked %s: %d\n", \ |
- 4*level, ' ', #className, \ |
- GetInstanceCount()); \ |
- } \ |
- if (NULL == SkInstanceCountHelper::GetChildren()) { \ |
- return GetInstanceCount(); \ |
- } \ |
- SkTArray<int (*)(int, bool)>* children = \ |
- SkInstanceCountHelper::GetChildren(); \ |
- int childCount = children->count(); \ |
- int count = GetInstanceCount(); \ |
- for (int i = 0; i < childCount; ++i) { \ |
- count -= (*(*children)[i])(level+1, cleanUp); \ |
- } \ |
- SkASSERT(count >= 0); \ |
- if (gPrintInstCount && childCount > 0 && count > 0) { \ |
- SkDebugf("%*c Leaked ???: %d\n", 4*(level + 1), ' ', count); \ |
- } \ |
- if (cleanUp) { \ |
- delete children; \ |
- SkInstanceCountHelper::GetChildren() = NULL; \ |
- } \ |
- return GetInstanceCount(); \ |
- } \ |
- \ |
- static void AddInstChild(int (*childCheckInstCnt)(int, bool)) { \ |
- if (CheckInstanceCount != childCheckInstCnt) { \ |
- SkAutoMutexAcquire ama(SkInstanceCountHelper::GetChildrenMutex()); \ |
- if (NULL == SkInstanceCountHelper::GetChildren()) { \ |
- SkInstanceCountHelper::GetChildren() = \ |
- new SkTArray<int (*)(int, bool)>; \ |
- } \ |
- SkInstanceCountHelper::GetChildren()->push_back(childCheckInstCnt); \ |
- } \ |
- } |
+ static void PrintAtExit() { |
+ int32_t leaks = Count(); |
+ if (gPrintInstCount && leaks > 0) { |
+ SkDebugf("Leaked %s: %d\n", Name(), leaks); |
+ } |
+ } |
+ // FIXME: Used publicly by unit tests. Seems like a bad idea in a DM world. |
+ static int32_t Count() { return sk_acquire_load(&gCount); } |
+ |
+ private: |
+ static int32_t gCount, gRegistered; |
+ }; |
+ // As template values, these will be deduplicated. (No one-definition rule problems.) |
+ template <typename T, const char*(Name)()> int32_t SkInstCount<T, Name>::gCount = 0; |
+ template <typename T, const char*(Name)()> int32_t SkInstCount<T, Name>::gRegistered = 0; |
#else |
-// Typically SK_ENABLE_INST_COUNT=0. Make sure the class declares public typedef INHERITED by |
-// causing a compile-time error if the typedef is missing. This way SK_ENABLE_INST_COUNT=1 stays |
-// compiling. |
-#define SK_DECLARE_INST_COUNT(className) static void AddInstChild() { INHERITED::AddInstChild(); } |
-#define SK_DECLARE_INST_COUNT_ROOT(className) static void AddInstChild() { } |
+ #define SK_DECLARE_INST_COUNT(T) |
#endif |
-// Following are deprecated. They are defined only for backwards API compatibility. |
-#define SK_DECLARE_INST_COUNT_TEMPLATE(className) SK_DECLARE_INST_COUNT(className) |
-#define SK_DEFINE_INST_COUNT(className) |
-#define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className) |
- |
#endif // SkInstCnt_DEFINED |