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|.
extractNameFromFunctionName(const char * 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
instance()64 static InstanceCounter* instance()
65 {
66 DEFINE_STATIC_LOCAL(InstanceCounter, self, ());
67 return &self;
68 }
69
70 private:
InstanceCounter()71 InstanceCounter() { }
72
73 Mutex m_mutex;
74 HashMap<String, int> m_counterMap;
75 };
76
incrementInstanceCount(const char * extractNameFuncName,void * ptr)77 void incrementInstanceCount(const char* extractNameFuncName, void* ptr)
78 {
79 String instanceName = extractNameFromFunctionName(extractNameFuncName);
80 InstanceCounter::instance()->incrementInstanceCount(instanceName, ptr);
81 }
82
decrementInstanceCount(const char * extractNameFuncName,void * ptr)83 void decrementInstanceCount(const char* extractNameFuncName, void* ptr)
84 {
85 String instanceName = extractNameFromFunctionName(extractNameFuncName);
86 InstanceCounter::instance()->decrementInstanceCount(instanceName, ptr);
87 }
88
dumpRefCountedInstanceCounts()89 String dumpRefCountedInstanceCounts()
90 {
91 return InstanceCounter::instance()->dump();
92 }
93
incrementInstanceCount(const String & instanceName,void * ptr)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
decrementInstanceCount(const String & instanceName,void * ptr)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
dump()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