|  | /* | 
|  | * Copyright 2012 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * 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 | 
|  | */ | 
|  | #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 | 
|  |  | 
|  | #include "SkOnce.h" | 
|  | #include "SkTArray.h" | 
|  | #include "SkThread.h" | 
|  | extern bool gPrintInstCount; | 
|  |  | 
|  | // 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);) | 
|  |  | 
|  | // 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);) | 
|  |  | 
|  | #define SK_DECLARE_INST_COUNT_INTERNAL(className, initStep)                 \ | 
|  | class SkInstanceCountHelper {                                           \ | 
|  | public:                                                                 \ | 
|  | SkInstanceCountHelper() {                                           \ | 
|  | SK_DECLARE_STATIC_ONCE(once);                                   \ | 
|  | SkOnce(&once, init, 0);                                         \ | 
|  | sk_atomic_inc(GetInstanceCountPtr());                           \ | 
|  | }                                                                   \ | 
|  | \ | 
|  | static void init(int) {                                             \ | 
|  | 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 SkBaseMutex& GetChildrenMutex() {                            \ | 
|  | SK_DECLARE_STATIC_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); \ | 
|  | }                                                                   \ | 
|  | } | 
|  |  | 
|  | #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() { } | 
|  | #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 |