1 /* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "InstanceCounter.h" 28 29 #include "wtf/HashMap.h" 30 #include "wtf/StdLibExtras.h" 31 #include "wtf/ThreadingPrimitives.h" 32 #include "wtf/text/StringBuilder.h" 33 #include "wtf/text/StringHash.h" 34 #include "wtf/text/WTFString.h" 35 36 namespace WTF { 37 38 #ifdef ENABLE_INSTANCE_COUNTER 39 40 // This function is used to stringify a typename T without using RTTI. 41 // The result of extractNameFunc<T>() is given as |funcName|. |extractNameFromFunctionName| then extracts a typename string from |funcName|. 42 String extractNameFromFunctionName(const char* funcName) 43 { 44 #if COMPILER(GCC) 45 const size_t prefixLength = sizeof("const char* WTF::extractNameFunc() [with T = ") - 1; 46 47 size_t funcNameLength = strlen(funcName); 48 ASSERT(funcNameLength > prefixLength + 1); 49 50 const char* funcNameWithoutPrefix = funcName + prefixLength; 51 return String(funcNameWithoutPrefix, funcNameLength - prefixLength - 1 /* last ] */); 52 #else 53 // FIXME: Support other compilers 54 ASSERT(false); 55 #endif 56 } 57 58 class InstanceCounter { 59 public: 60 void incrementInstanceCount(const String& instanceName, void* ptr); 61 void decrementInstanceCount(const String& instanceName, void* ptr); 62 String dump(); 63 64 static InstanceCounter* instance() 65 { 66 DEFINE_STATIC_LOCAL(InstanceCounter, self, ()); 67 return &self; 68 } 69 70 private: 71 InstanceCounter() { } 72 73 Mutex m_mutex; 74 HashMap<String, int> m_counterMap; 75 }; 76 77 void incrementInstanceCount(const char* extractNameFuncName, void* ptr) 78 { 79 String instanceName = extractNameFromFunctionName(extractNameFuncName); 80 InstanceCounter::instance()->incrementInstanceCount(instanceName, ptr); 81 } 82 83 void decrementInstanceCount(const char* extractNameFuncName, void* ptr) 84 { 85 String instanceName = extractNameFromFunctionName(extractNameFuncName); 86 InstanceCounter::instance()->decrementInstanceCount(instanceName, ptr); 87 } 88 89 String dumpRefCountedInstanceCounts() 90 { 91 return InstanceCounter::instance()->dump(); 92 } 93 94 void InstanceCounter::incrementInstanceCount(const String& instanceName, void* ptr) 95 { 96 MutexLocker locker(m_mutex); 97 HashMap<String, int>::AddResult result = m_counterMap.add(instanceName, 1); 98 if (!result.isNewEntry) 99 ++(result.iterator->value); 100 } 101 102 void InstanceCounter::decrementInstanceCount(const String& instanceName, void* ptr) 103 { 104 MutexLocker locker(m_mutex); 105 HashMap<String, int>::iterator it = m_counterMap.find(instanceName); 106 ASSERT(it != m_counterMap.end()); 107 108 --(it->value); 109 if (!it->value) 110 m_counterMap.remove(it); 111 } 112 113 String InstanceCounter::dump() 114 { 115 MutexLocker locker(m_mutex); 116 117 StringBuilder builder; 118 119 builder.append("{"); 120 HashMap<String, int>::iterator it = m_counterMap.begin(); 121 HashMap<String, int>::iterator itEnd = m_counterMap.end(); 122 for (; it != itEnd; ++it) { 123 if (it != m_counterMap.begin()) 124 builder.append(","); 125 builder.append("\""); 126 builder.append(it->key); 127 builder.append("\": "); 128 builder.append(String::number(it->value)); 129 } 130 builder.append("}"); 131 132 return builder.toString(); 133 } 134 135 #else 136 137 String dumpRefCountedInstanceCounts() 138 { 139 return String("{}"); 140 } 141 142 #endif // ENABLE_INSTANCE_COUNTER 143 144 } // namespace WTF 145