| /* |
| * Copyright (C) 2012 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: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * 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. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT |
| * OWNER OR 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. |
| */ |
| |
| #ifndef MemoryInstrumentation_h |
| #define MemoryInstrumentation_h |
| |
| #include "wtf/OwnPtr.h" |
| #include "wtf/PassOwnPtr.h" |
| #include "wtf/RefPtr.h" |
| #include "wtf/WTFExport.h" |
| |
| #define DEBUG_POINTER_INSTRUMENTATION 0 |
| |
| namespace WTF { |
| |
| class MemoryClassInfo; |
| class MemoryObjectInfo; |
| class MemoryInstrumentation; |
| |
| typedef const char* MemoryObjectType; |
| |
| enum MemberType { |
| PointerMember, |
| ReferenceMember, |
| RetainingPointer, |
| LastMemberTypeEntry |
| }; |
| |
| template <typename B, typename D> |
| struct IsBaseOf { |
| typedef char (&Yes)[1]; |
| typedef char (&No)[2]; |
| |
| template <typename U, typename V> |
| struct Host { |
| operator U*() const; |
| operator V*(); |
| }; |
| |
| template <typename T> static Yes checkBase(D*, T); |
| static No checkBase(B*, int); |
| |
| static const bool value = sizeof(checkBase(Host<B,D>(), int())) == sizeof(Yes); |
| }; |
| |
| template <bool B, class T = void> |
| struct EnableIf { |
| typedef T Type; |
| }; |
| |
| template <class T> |
| struct EnableIf<false, T> {}; |
| |
| class MemoryReporterTag {}; |
| |
| class MemoryInstrumentationClient { |
| public: |
| virtual ~MemoryInstrumentationClient() { } |
| virtual void countObjectSize(const void*, MemoryObjectType, size_t) = 0; |
| virtual bool visited(const void*) = 0; |
| virtual bool checkCountedObject(const void*) = 0; |
| |
| virtual void reportNode(const MemoryObjectInfo&) = 0; |
| virtual void reportEdge(const void* target, const char* edgeName, MemberType) = 0; |
| virtual void reportLeaf(const MemoryObjectInfo&, const char* edgeName) = 0; |
| virtual void reportBaseAddress(const void* base, const void* real) = 0; |
| virtual int registerString(const char*) = 0; |
| }; |
| |
| class WTF_EXPORT MemoryInstrumentation { |
| public: |
| explicit MemoryInstrumentation(MemoryInstrumentationClient*); |
| virtual ~MemoryInstrumentation(); |
| |
| template <typename T> void addRootObject(const T& t, MemoryObjectType objectType = 0) |
| { |
| MemberTypeTraits<T>::addRootObject(this, t, objectType); |
| processDeferredObjects(); |
| } |
| |
| template <typename T> void addRootObject(const OwnPtr<T>&, MemoryObjectType = 0); // Link time guard. |
| template <typename T> void addRootObject(const RefPtr<T>&, MemoryObjectType = 0); // Link time guard. |
| |
| template <int> |
| struct InstrumentationSelector { |
| template <typename T> static void reportObjectMemoryUsage(const T*, MemoryObjectInfo*); |
| }; |
| |
| template <typename Type> |
| class IsInstrumented { |
| class yes { |
| char m; |
| }; |
| |
| class no { |
| yes m[2]; |
| }; |
| |
| struct BaseMixin { |
| void reportMemoryUsage(MemoryObjectInfo*) const { } |
| }; |
| |
| struct Base : public Type, public BaseMixin { |
| // Provide expicit destructor without definition to avoid MSVC warning "destructor could |
| // not be generated because a base class destructor is inaccessible." |
| ~Base(); |
| }; |
| |
| template <typename T, T t> class Helper { }; |
| |
| template <typename U> static no deduce(U*, Helper<void (BaseMixin::*)(MemoryObjectInfo*) const, &U::reportMemoryUsage>* = 0); |
| static yes deduce(...); |
| |
| public: |
| static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0))); |
| |
| }; |
| |
| protected: |
| class WTF_EXPORT WrapperBase { |
| public: |
| WrapperBase(MemoryObjectType, const void* pointer); |
| virtual ~WrapperBase() { } |
| void process(MemoryInstrumentation*); |
| void processPointer(MemoryInstrumentation*, bool isRoot); |
| void processRootObjectRef(MemoryInstrumentation*); |
| |
| protected: |
| virtual void callReportMemoryUsage(MemoryObjectInfo*) = 0; |
| const void* m_pointer; |
| const MemoryObjectType m_ownerObjectType; |
| |
| private: |
| #if DEBUG_POINTER_INSTRUMENTATION |
| static const int s_maxCallStackSize = 32; |
| void* m_callStack[s_maxCallStackSize]; |
| int m_callStackSize; |
| #endif |
| }; |
| |
| private: |
| void countObjectSize(const void* object, MemoryObjectType objectType, size_t size) { m_client->countObjectSize(object, objectType, size); } |
| bool visited(const void* pointer) { return m_client->visited(pointer); } |
| bool checkCountedObject(const void* pointer) { return m_client->checkCountedObject(pointer); } |
| |
| void reportEdge(const void* target, const char* edgeName, MemberType); |
| |
| virtual void deferObject(PassOwnPtr<WrapperBase>) = 0; |
| virtual void processDeferredObjects() = 0; |
| |
| static MemoryObjectType getObjectType(MemoryObjectInfo*); |
| |
| friend class MemoryObjectInfo; |
| friend class MemoryClassInfo; |
| |
| template<typename T> class Wrapper : public WrapperBase { |
| public: |
| Wrapper(const T* pointer, MemoryObjectType); |
| |
| protected: |
| virtual void callReportMemoryUsage(MemoryObjectInfo*) OVERRIDE; |
| }; |
| |
| template<typename T> void addObject(const T& t, MemoryObjectInfo* ownerObjectInfo, const char* edgeName, MemberType memberType) |
| { |
| MemberTypeTraits<T>::addObject(this, t, ownerObjectInfo, edgeName, memberType); |
| } |
| void addRawBuffer(const void* buffer, MemoryObjectType ownerObjectType, size_t size, const char* className = 0, const char* edgeName = 0) |
| { |
| if (!buffer || visited(buffer)) |
| return; |
| countObjectSize(buffer, ownerObjectType, size); |
| reportLinkToBuffer(buffer, ownerObjectType, size, className, edgeName); |
| } |
| void reportLinkToBuffer(const void* buffer, MemoryObjectType ownerObjectType, size_t, const char* nodeName, const char* edgeName); |
| |
| template<typename T> |
| struct MemberTypeTraits { // Default ReferenceMember implementation. |
| static void addObject(MemoryInstrumentation* instrumentation, const T& t, MemoryObjectInfo* ownerObjectInfo, const char* edgeName, MemberType) |
| { |
| instrumentation->addObjectImpl(&t, ownerObjectInfo, ReferenceMember, edgeName); |
| } |
| |
| static void addRootObject(MemoryInstrumentation* instrumentation, const T& t, MemoryObjectType objectType) |
| { |
| Wrapper<T>(&t, objectType).processRootObjectRef(instrumentation); |
| } |
| }; |
| |
| template<typename T> |
| struct MemberTypeTraits<T*> { // Custom PointerMember implementation. |
| static void addObject(MemoryInstrumentation* instrumentation, const T* const& t, MemoryObjectInfo* ownerObjectInfo, const char* edgeName, MemberType memberType) |
| { |
| instrumentation->addObjectImpl(t, ownerObjectInfo, memberType != LastMemberTypeEntry ? memberType : PointerMember, edgeName); |
| } |
| |
| static void addRootObject(MemoryInstrumentation* instrumentation, const T* const& t, MemoryObjectType objectType) |
| { |
| if (t && !instrumentation->visited(t)) |
| Wrapper<T>(t, objectType).processPointer(instrumentation, true); |
| } |
| }; |
| |
| template<typename T> void addObjectImpl(const T*, MemoryObjectInfo*, MemberType, const char* edgeName); |
| template<typename T> void addObjectImpl(const OwnPtr<T>*, MemoryObjectInfo*, MemberType, const char* edgeName); |
| template<typename T> void addObjectImpl(const RefPtr<T>*, MemoryObjectInfo*, MemberType, const char* edgeName); |
| |
| MemoryInstrumentationClient* m_client; |
| }; |
| |
| // We are trying to keep the signature of the function as small as possible |
| // because it significantly affects the binary size. |
| // We caluclates class name for 624 classes at the moment. |
| // So one extra byte of the function signature increases the binary size to 624 extra bytes. |
| #if COMPILER(MSVC) |
| template <typename T> struct FN { |
| static char* fn() { return const_cast<char*>(__FUNCTION__); } |
| }; |
| |
| template <typename T> char* fn() { return FN<T>::fn(); } |
| #else |
| template <typename T> char* fn() { return const_cast<char*>(__PRETTY_FUNCTION__); } |
| #endif |
| |
| class WTF_EXPORT MemoryClassInfo { |
| public: |
| template<typename T> |
| MemoryClassInfo(MemoryObjectInfo* memoryObjectInfo, const T* pointer, MemoryObjectType objectType = 0, size_t actualSize = sizeof(T)) |
| : m_memoryObjectInfo(memoryObjectInfo) |
| , m_memoryInstrumentation(0) |
| , m_objectType(0) |
| , m_skipMembers(false) |
| { |
| init(pointer, fn<T>(), objectType, actualSize); |
| } |
| |
| template<typename M> void addMember(const M& member, const char* edgeName = 0, MemberType memberType = LastMemberTypeEntry) |
| { |
| if (!m_skipMembers) |
| m_memoryInstrumentation->addObject(member, m_memoryObjectInfo, edgeName, memberType); |
| } |
| |
| void addRawBuffer(const void* buffer, size_t, const char* className = 0, const char* edgeName = 0); |
| void addPrivateBuffer(size_t, MemoryObjectType ownerObjectType = 0, const char* className = 0, const char* edgeName = 0); |
| void setCustomAllocation(bool); |
| |
| void addWeakPointer(void*) { } |
| template<typename M> void ignoreMember(const M&) { } |
| |
| static void callReportObjectInfo(MemoryObjectInfo*, const void* pointer, const char* stringWithClassName, MemoryObjectType, size_t actualSize); |
| |
| private: |
| void init(const void* pointer, const char* stringWithClassName, MemoryObjectType, size_t actualSize); |
| |
| MemoryObjectInfo* m_memoryObjectInfo; |
| MemoryInstrumentation* m_memoryInstrumentation; |
| MemoryObjectType m_objectType; |
| bool m_skipMembers; |
| }; |
| |
| template <> |
| template <typename T> |
| void MemoryInstrumentation::InstrumentationSelector<true>::reportObjectMemoryUsage(const T* object, MemoryObjectInfo* memoryObjectInfo) |
| { |
| object->reportMemoryUsage(memoryObjectInfo); |
| } |
| |
| template <> |
| template <typename T> |
| void MemoryInstrumentation::InstrumentationSelector<false>::reportObjectMemoryUsage(const T* object, MemoryObjectInfo* memoryObjectInfo) |
| { |
| MemoryClassInfo::callReportObjectInfo(memoryObjectInfo, object, fn<T>(), 0, sizeof(T)); |
| } |
| |
| template <typename T> |
| typename EnableIf<IsBaseOf<MemoryReporterTag, T>::value, void>::Type reportMemoryUsage(const T* object, MemoryObjectInfo* memoryObjectInfo) |
| { |
| COMPILE_ASSERT(sizeof(T), WTF_MemoryInstrumentation_Need_Complete_Type); |
| object->reportMemoryUsage(memoryObjectInfo); |
| } |
| |
| template <typename T> |
| typename EnableIf<!IsBaseOf<MemoryReporterTag, T>::value, void>::Type reportMemoryUsage(const T* object, MemoryObjectInfo* memoryObjectInfo) |
| { |
| COMPILE_ASSERT(sizeof(T), WTF_MemoryInstrumentation_Need_Complete_Type); |
| MemoryInstrumentation::InstrumentationSelector<MemoryInstrumentation::IsInstrumented<T>::result>::reportObjectMemoryUsage(object, memoryObjectInfo); |
| } |
| |
| template<typename T> |
| void MemoryInstrumentation::addObjectImpl(const T* object, MemoryObjectInfo* ownerObjectInfo, MemberType memberType, const char* edgeName) |
| { |
| if (memberType == PointerMember) |
| return; |
| if (memberType == ReferenceMember) |
| reportMemoryUsage(object, ownerObjectInfo); |
| else { |
| if (!object) |
| return; |
| reportEdge(object, edgeName, memberType); |
| if (visited(object)) |
| return; |
| deferObject(adoptPtr(new Wrapper<T>(object, getObjectType(ownerObjectInfo)))); |
| } |
| } |
| |
| template<typename T> |
| void MemoryInstrumentation::addObjectImpl(const OwnPtr<T>* object, MemoryObjectInfo* ownerObjectInfo, MemberType memberType, const char* edgeName) |
| { |
| if (memberType == PointerMember && !visited(object)) |
| countObjectSize(object, getObjectType(ownerObjectInfo), sizeof(*object)); |
| addObjectImpl(object->get(), ownerObjectInfo, RetainingPointer, edgeName); |
| } |
| |
| template<typename T> |
| void MemoryInstrumentation::addObjectImpl(const RefPtr<T>* object, MemoryObjectInfo* ownerObjectInfo, MemberType memberType, const char* edgeName) |
| { |
| if (memberType == PointerMember && !visited(object)) |
| countObjectSize(object, getObjectType(ownerObjectInfo), sizeof(*object)); |
| addObjectImpl(object->get(), ownerObjectInfo, RetainingPointer, edgeName); |
| } |
| |
| template<typename T> |
| MemoryInstrumentation::Wrapper<T>::Wrapper(const T* pointer, MemoryObjectType ownerObjectType) |
| : WrapperBase(ownerObjectType, pointer) |
| { |
| } |
| |
| template<typename T> |
| void MemoryInstrumentation::Wrapper<T>::callReportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) |
| { |
| reportMemoryUsage(static_cast<const T*>(m_pointer), memoryObjectInfo); |
| } |
| |
| // Link time guard for classes with external memory instrumentation. |
| template<typename T, size_t inlineCapacity> class Vector; |
| template<typename T, size_t inlineCapacity> void reportMemoryUsage(const Vector<T, inlineCapacity>*, MemoryObjectInfo*); |
| |
| template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg> class HashMap; |
| template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg> void reportMemoryUsage(const HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>*, MemoryObjectInfo*); |
| |
| template<typename ValueArg, typename HashArg, typename TraitsArg> class HashCountedSet; |
| template<typename ValueArg, typename HashArg, typename TraitsArg> void reportMemoryUsage(const HashCountedSet<ValueArg, HashArg, TraitsArg>*, MemoryObjectInfo*); |
| |
| template<typename ValueArg, size_t inlineCapacity, typename HashArg> class ListHashSet; |
| template<typename ValueArg, size_t inlineCapacity, typename HashArg> void reportMemoryUsage(const ListHashSet<ValueArg, inlineCapacity, HashArg>*, MemoryObjectInfo*); |
| |
| class String; |
| void reportMemoryUsage(const String*, MemoryObjectInfo*); |
| |
| class StringImpl; |
| void reportMemoryUsage(const StringImpl*, MemoryObjectInfo*); |
| |
| class AtomicString; |
| void reportMemoryUsage(const AtomicString*, MemoryObjectInfo*); |
| |
| class CString; |
| void reportMemoryUsage(const CString*, MemoryObjectInfo*); |
| |
| class CStringBuffer; |
| void reportMemoryUsage(const CStringBuffer*, MemoryObjectInfo*); |
| |
| class ParsedURL; |
| void reportMemoryUsage(const ParsedURL*, MemoryObjectInfo*); |
| |
| class URLString; |
| void reportMemoryUsage(const URLString*, MemoryObjectInfo*); |
| |
| } // namespace WTF |
| |
| using WTF::MemoryReporterTag; |
| |
| #endif // !defined(MemoryInstrumentation_h) |