| /* |
| * Copyright (C) 2013 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "sky/engine/wtf/InstanceCounter.h" |
| |
| #include "sky/engine/wtf/HashMap.h" |
| #include "sky/engine/wtf/StdLibExtras.h" |
| #include "sky/engine/wtf/ThreadingPrimitives.h" |
| #include "sky/engine/wtf/text/StringBuilder.h" |
| #include "sky/engine/wtf/text/StringHash.h" |
| #include "sky/engine/wtf/text/WTFString.h" |
| |
| namespace WTF { |
| |
| #if ENABLE(INSTANCE_COUNTER) || ENABLE(GC_PROFILING) |
| |
| #if COMPILER(CLANG) |
| const size_t extractNameFunctionPrefixLength = sizeof("const char *WTF::extractNameFunction() [T = ") - 1; |
| const size_t extractNameFunctionPostfixLength = sizeof("]") - 1; |
| #elif COMPILER(GCC) |
| const size_t extractNameFunctionPrefixLength = sizeof("const char* WTF::extractNameFunction() [with T = ") - 1; |
| const size_t extractNameFunctionPostfixLength = sizeof("]") - 1; |
| #else |
| #warning "Extracting typename is supported only in compiler GCC, CLANG and MSVC at this moment" |
| #endif |
| |
| // This function is used to stringify a typename T without using RTTI. |
| // The result of extractNameFunction<T>() is given as |funcName|. |extractTypeNameFromFunctionName| then extracts a typename string from |funcName|. |
| String extractTypeNameFromFunctionName(const char* funcName) |
| { |
| #if COMPILER(CLANG) || COMPILER(GCC) |
| size_t funcNameLength = strlen(funcName); |
| ASSERT(funcNameLength > extractNameFunctionPrefixLength + extractNameFunctionPostfixLength); |
| |
| const char* funcNameWithoutPrefix = funcName + extractNameFunctionPrefixLength; |
| return String(funcNameWithoutPrefix, funcNameLength - extractNameFunctionPrefixLength - extractNameFunctionPostfixLength); |
| #else |
| return String("unknown"); |
| #endif |
| } |
| |
| class InstanceCounter { |
| public: |
| void incrementInstanceCount(const String& instanceName, void* ptr); |
| void decrementInstanceCount(const String& instanceName, void* ptr); |
| String dump(); |
| |
| static InstanceCounter* instance() |
| { |
| DEFINE_STATIC_LOCAL(InstanceCounter, self, ()); |
| return &self; |
| } |
| |
| private: |
| InstanceCounter() { } |
| |
| Mutex m_mutex; |
| HashMap<String, int> m_counterMap; |
| }; |
| |
| void incrementInstanceCount(const char* extractNameFunctionName, void* ptr) |
| { |
| String instanceName = extractTypeNameFromFunctionName(extractNameFunctionName); |
| InstanceCounter::instance()->incrementInstanceCount(instanceName, ptr); |
| } |
| |
| void decrementInstanceCount(const char* extractNameFunctionName, void* ptr) |
| { |
| String instanceName = extractTypeNameFromFunctionName(extractNameFunctionName); |
| InstanceCounter::instance()->decrementInstanceCount(instanceName, ptr); |
| } |
| |
| String dumpRefCountedInstanceCounts() |
| { |
| return InstanceCounter::instance()->dump(); |
| } |
| |
| void InstanceCounter::incrementInstanceCount(const String& instanceName, void* ptr) |
| { |
| MutexLocker locker(m_mutex); |
| HashMap<String, int>::AddResult result = m_counterMap.add(instanceName, 1); |
| if (!result.isNewEntry) |
| ++(result.storedValue->value); |
| } |
| |
| void InstanceCounter::decrementInstanceCount(const String& instanceName, void* ptr) |
| { |
| MutexLocker locker(m_mutex); |
| HashMap<String, int>::iterator it = m_counterMap.find(instanceName); |
| ASSERT(it != m_counterMap.end()); |
| |
| --(it->value); |
| if (!it->value) |
| m_counterMap.remove(it); |
| } |
| |
| String InstanceCounter::dump() |
| { |
| MutexLocker locker(m_mutex); |
| |
| StringBuilder builder; |
| |
| builder.append("{"); |
| HashMap<String, int>::iterator it = m_counterMap.begin(); |
| HashMap<String, int>::iterator itEnd = m_counterMap.end(); |
| for (; it != itEnd; ++it) { |
| if (it != m_counterMap.begin()) |
| builder.append(","); |
| builder.append("\""); |
| builder.append(it->key); |
| builder.append("\": "); |
| builder.append(String::number(it->value)); |
| } |
| builder.append("}"); |
| |
| return builder.toString(); |
| } |
| |
| #else |
| |
| String dumpRefCountedInstanceCounts() |
| { |
| return String("{}"); |
| } |
| |
| #endif // ENABLE(INSTANCE_COUNTER) || ENABLE(GC_PROFILING) |
| |
| } // namespace WTF |