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 #if ENABLE(INSTANCE_COUNTER) || ENABLE(GC_PROFILING) 39 40 #if COMPILER(CLANG) 41 const size_t extractNameFunctionPrefixLength = sizeof("const char *WTF::extractNameFunction() [T = ") - 1; 42 const size_t extractNameFunctionPostfixLength = sizeof("]") - 1; 43 #elif COMPILER(GCC) 44 const size_t extractNameFunctionPrefixLength = sizeof("const char* WTF::extractNameFunction() [with T = ") - 1; 45 const size_t extractNameFunctionPostfixLength = sizeof("]") - 1; 46 #elif COMPILER(MSVC) 47 const size_t extractNameFunctionPrefixLength = sizeof("const char *__cdecl WTF::extractNameFunction<class ") - 1; 48 const size_t extractNameFunctionPostfixLength = sizeof(">(void)") - 1; 49 #else 50 #warning "Extracting typename is supported only in compiler GCC, CLANG and MSVC at this moment" 51 #endif 52 53 // This function is used to stringify a typename T without using RTTI. 54 // The result of extractNameFunction<T>() is given as |funcName|. |extractTypeNameFromFunctionName| then extracts a typename string from |funcName|. 55 String extractTypeNameFromFunctionName(const char* funcName) 56 { 57 #if COMPILER(CLANG) || COMPILER(GCC) || COMPILER(MSVC) 58 size_t funcNameLength = strlen(funcName); 59 ASSERT(funcNameLength > extractNameFunctionPrefixLength + extractNameFunctionPostfixLength); 60 61 const char* funcNameWithoutPrefix = funcName + extractNameFunctionPrefixLength; 62 return String(funcNameWithoutPrefix, funcNameLength - extractNameFunctionPrefixLength - extractNameFunctionPostfixLength); 63 #else 64 return String("unknown"); 65 #endif 66 } 67 68 class InstanceCounter { 69 public: 70 void incrementInstanceCount(const String& instanceName, void* ptr); 71 void decrementInstanceCount(const String& instanceName, void* ptr); 72 String dump(); 73 74 static InstanceCounter* instance() 75 { 76 DEFINE_STATIC_LOCAL(InstanceCounter, self, ()); 77 return &self; 78 } 79 80 private: 81 InstanceCounter() { } 82 83 Mutex m_mutex; 84 HashMap<String, int> m_counterMap; 85 }; 86 87 void incrementInstanceCount(const char* extractNameFunctionName, void* ptr) 88 { 89 String instanceName = extractTypeNameFromFunctionName(extractNameFunctionName); 90 InstanceCounter::instance()->incrementInstanceCount(instanceName, ptr); 91 } 92 93 void decrementInstanceCount(const char* extractNameFunctionName, void* ptr) 94 { 95 String instanceName = extractTypeNameFromFunctionName(extractNameFunctionName); 96 InstanceCounter::instance()->decrementInstanceCount(instanceName, ptr); 97 } 98 99 String dumpRefCountedInstanceCounts() 100 { 101 return InstanceCounter::instance()->dump(); 102 } 103 104 void InstanceCounter::incrementInstanceCount(const String& instanceName, void* ptr) 105 { 106 MutexLocker locker(m_mutex); 107 HashMap<String, int>::AddResult result = m_counterMap.add(instanceName, 1); 108 if (!result.isNewEntry) 109 ++(result.storedValue->value); 110 } 111 112 void InstanceCounter::decrementInstanceCount(const String& instanceName, void* ptr) 113 { 114 MutexLocker locker(m_mutex); 115 HashMap<String, int>::iterator it = m_counterMap.find(instanceName); 116 ASSERT(it != m_counterMap.end()); 117 118 --(it->value); 119 if (!it->value) 120 m_counterMap.remove(it); 121 } 122 123 String InstanceCounter::dump() 124 { 125 MutexLocker locker(m_mutex); 126 127 StringBuilder builder; 128 129 builder.append('{'); 130 HashMap<String, int>::iterator it = m_counterMap.begin(); 131 HashMap<String, int>::iterator itEnd = m_counterMap.end(); 132 for (; it != itEnd; ++it) { 133 if (it != m_counterMap.begin()) 134 builder.append(','); 135 builder.append('"'); 136 builder.append(it->key); 137 builder.appendLiteral("\": "); 138 builder.appendNumber(it->value); 139 } 140 builder.append('}'); 141 142 return builder.toString(); 143 } 144 145 #else 146 147 String dumpRefCountedInstanceCounts() 148 { 149 return String("{}"); 150 } 151 152 #endif // ENABLE(INSTANCE_COUNTER) || ENABLE(GC_PROFILING) 153 154 } // namespace WTF 155