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