Memory instrumentation: make sure each edge is reported only once
[WebKit-https.git] / Source / WTF / wtf / MemoryInstrumentation.cpp
1 /*
2  * Copyright (C) 2012 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "MemoryInstrumentation.h"
33
34 #include <wtf/MemoryObjectInfo.h>
35
36 #if DEBUG_POINTER_INSTRUMENTATION
37 #include <stdio.h>
38 #include <wtf/Assertions.h>
39 #endif
40
41 namespace WTF {
42
43 MemoryInstrumentation::MemoryInstrumentation(MemoryInstrumentationClient* client)
44     : m_client(client)
45     , m_rootObjectInfo(adoptPtr(new MemoryObjectInfo(this, 0, 0)))
46 {
47 }
48
49 MemoryInstrumentation::~MemoryInstrumentation()
50 {
51 }
52
53 void MemoryInstrumentation::reportEdge(MemoryObjectInfo* ownerObjectInfo, const void* target, const char* name)
54 {
55     m_client->reportEdge(ownerObjectInfo->reportedPointer(), target, name);
56 }
57
58 MemoryObjectType MemoryInstrumentation::getObjectType(MemoryObjectInfo* objectInfo)
59 {
60     return objectInfo->objectType();
61 }
62
63 void MemoryInstrumentation::callReportObjectInfo(MemoryObjectInfo* memoryObjectInfo, const void* pointer, MemoryObjectType objectType, size_t objectSize)
64 {
65     memoryObjectInfo->reportObjectInfo(pointer, objectType, objectSize);
66 }
67
68 void MemoryInstrumentation::reportLinkToBuffer(const void* owner, const void* buffer, MemoryObjectType ownerObjectType, size_t size, const char* nodeName, const char* edgeName)
69 {
70     MemoryObjectInfo memoryObjectInfo(this, ownerObjectType, 0);
71     memoryObjectInfo.reportObjectInfo(buffer, ownerObjectType, size);
72     memoryObjectInfo.setName(nodeName);
73     m_client->reportLeaf(owner, memoryObjectInfo, edgeName);
74 }
75
76 MemoryInstrumentation::InstrumentedPointerBase::InstrumentedPointerBase(MemoryObjectInfo* memoryObjectInfo, const void* pointer)
77     : m_pointer(pointer)
78     , m_ownerObjectType(memoryObjectInfo->objectType())
79 {
80 #if DEBUG_POINTER_INSTRUMENTATION
81     m_callStackSize = s_maxCallStackSize;
82     WTFGetBacktrace(m_callStack, &m_callStackSize);
83 #endif
84 }
85
86 void MemoryInstrumentation::InstrumentedPointerBase::process(MemoryInstrumentation* memoryInstrumentation)
87 {
88     MemoryObjectInfo memoryObjectInfo(memoryInstrumentation, m_ownerObjectType, m_pointer);
89     callReportMemoryUsage(&memoryObjectInfo);
90
91     const void* realAddress = memoryObjectInfo.reportedPointer();
92     ASSERT(realAddress);
93     if (realAddress != m_pointer) {
94         memoryInstrumentation->m_client->reportBaseAddress(m_pointer, realAddress);
95         if (!memoryObjectInfo.firstVisit())
96             return;
97     }
98     memoryInstrumentation->countObjectSize(realAddress, memoryObjectInfo.objectType(), memoryObjectInfo.objectSize());
99     memoryInstrumentation->m_client->reportNode(memoryObjectInfo);
100     if (!memoryInstrumentation->checkCountedObject(realAddress)) {
101 #if DEBUG_POINTER_INSTRUMENTATION
102         fputs("Unknown object counted:\n", stderr);
103         WTFPrintBacktrace(m_callStack, m_callStackSize);
104 #endif
105     }
106 }
107
108 void MemoryClassInfo::init(const void* objectAddress, MemoryObjectType objectType, size_t actualSize)
109 {
110     m_memoryObjectInfo->reportObjectInfo(objectAddress, objectType, actualSize);
111     m_memoryInstrumentation = m_memoryObjectInfo->memoryInstrumentation();
112     m_objectType = m_memoryObjectInfo->objectType();
113     m_skipMembers = !m_memoryObjectInfo->firstVisit();
114 }
115
116 void MemoryClassInfo::addRawBuffer(const void* buffer, size_t size, const char* nodeName, const char* edgeName)
117 {
118     if (!m_skipMembers)
119         m_memoryInstrumentation->addRawBuffer(m_memoryObjectInfo->reportedPointer(), buffer, m_objectType, size, nodeName, edgeName);
120 }
121
122 void MemoryClassInfo::addPrivateBuffer(size_t size, MemoryObjectType ownerObjectType, const char* nodeName, const char* edgeName)
123 {
124     if (!size)
125         return;
126     if (m_skipMembers)
127         return;
128     if (!ownerObjectType)
129         ownerObjectType = m_objectType;
130     m_memoryInstrumentation->countObjectSize(0, ownerObjectType, size);
131     m_memoryInstrumentation->reportLinkToBuffer(m_memoryObjectInfo->reportedPointer(), 0, ownerObjectType, size, nodeName, edgeName);
132 }
133
134 } // namespace WTF