Home | History | Annotate | Download | only in wtf
      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