• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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