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