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_TRACING)
39
40 #if COMPILER(CLANG)
41 const size_t extractNameFunctionPrefixLength = sizeof("const char *WTF::extractNameFunction() [T = ") - 1;
42 const size_t extractNameFunctionPostfixLength = 1;
43 #elif COMPILER(GCC)
44 const size_t extractNameFunctionPrefixLength = sizeof("const char* WTF::extractNameFunction() [with T = ") - 1;
45 const 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|.
extractTypeNameFromFunctionName(const char * funcName)52 String 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
65 class InstanceCounter {
66 public:
67 void incrementInstanceCount(const String& instanceName, void* ptr);
68 void decrementInstanceCount(const String& instanceName, void* ptr);
69 String dump();
70
instance()71 static InstanceCounter* instance()
72 {
73 DEFINE_STATIC_LOCAL(InstanceCounter, self, ());
74 return &self;
75 }
76
77 private:
InstanceCounter()78 InstanceCounter() { }
79
80 Mutex m_mutex;
81 HashMap<String, int> m_counterMap;
82 };
83
incrementInstanceCount(const char * extractNameFunctionName,void * ptr)84 void incrementInstanceCount(const char* extractNameFunctionName, void* ptr)
85 {
86 String instanceName = extractTypeNameFromFunctionName(extractNameFunctionName);
87 InstanceCounter::instance()->incrementInstanceCount(instanceName, ptr);
88 }
89
decrementInstanceCount(const char * extractNameFunctionName,void * ptr)90 void decrementInstanceCount(const char* extractNameFunctionName, void* ptr)
91 {
92 String instanceName = extractTypeNameFromFunctionName(extractNameFunctionName);
93 InstanceCounter::instance()->decrementInstanceCount(instanceName, ptr);
94 }
95
dumpRefCountedInstanceCounts()96 String dumpRefCountedInstanceCounts()
97 {
98 return InstanceCounter::instance()->dump();
99 }
100
incrementInstanceCount(const String & instanceName,void * ptr)101 void 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
decrementInstanceCount(const String & instanceName,void * ptr)109 void 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
dump()120 String 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
144 String dumpRefCountedInstanceCounts()
145 {
146 return String("{}");
147 }
148
149 #endif // ENABLE(INSTANCE_COUNTER) || ENABLE(GC_TRACING)
150
151 } // namespace WTF
152