blob: a1ee06d5299d82e842a0d03f3ecc4015a820f6ad [file] [log] [blame]
/*
* 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 "wtf/InstanceCounter.h"
#include "wtf/HashMap.h"
#include "wtf/StdLibExtras.h"
#include "wtf/ThreadingPrimitives.h"
#include "wtf/text/StringBuilder.h"
#include "wtf/text/StringHash.h"
#include "wtf/text/WTFString.h"
namespace WTF {
#if ENABLE(INSTANCE_COUNTER) || ENABLE(DETAILED_MEMORY_INFRA)
#if COMPILER(CLANG)
const size_t stringWithTypeNamePrefixLength = sizeof("const char *WTF::getStringWithTypeName() [T = ") - 1;
const size_t stringWithTypeNamePostfixLength = sizeof("]") - 1;
#elif COMPILER(GCC)
const size_t stringWithTypeNamePrefixLength = sizeof("const char* WTF::getStringWithTypeName() [with T = ") - 1;
const size_t stringWithTypeNamePostfixLength = sizeof("]") - 1;
#elif COMPILER(MSVC)
const size_t stringWithTypeNamePrefixLength = sizeof("const char *__cdecl WTF::getStringWithTypeName<class ") - 1;
const size_t stringWithTypeNamePostfixLength = sizeof(">(void)") - 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 stringWithTypeName<T>() is given as |funcName|. |extractTypeNameFromFunctionName| then extracts a typename string from |funcName|.
String extractTypeNameFromFunctionName(const char* funcName)
{
#if COMPILER(CLANG) || COMPILER(GCC) || COMPILER(MSVC)
size_t funcNameLength = strlen(funcName);
ASSERT(funcNameLength > stringWithTypeNamePrefixLength + stringWithTypeNamePostfixLength);
const char* funcNameWithoutPrefix = funcName + stringWithTypeNamePrefixLength;
return String(funcNameWithoutPrefix, funcNameLength - stringWithTypeNamePrefixLength - stringWithTypeNamePostfixLength);
#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* stringWithTypeNameName, void* ptr)
{
String instanceName = extractTypeNameFromFunctionName(stringWithTypeNameName);
InstanceCounter::instance()->incrementInstanceCount(instanceName, ptr);
}
void decrementInstanceCount(const char* stringWithTypeNameName, void* ptr)
{
String instanceName = extractTypeNameFromFunctionName(stringWithTypeNameName);
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.appendLiteral("\": ");
builder.appendNumber(it->value);
}
builder.append('}');
return builder.toString();
}
#else
String dumpRefCountedInstanceCounts()
{
return String("{}");
}
#endif // ENABLE(INSTANCE_COUNTER) || ENABLE(DETAILED_MEMORY_INFRA)
} // namespace WTF