blob: 82e4b9834a2fc7ea0bba486077f3046b5e7bdddc [file] [log] [blame]
/*
* 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.
*/
#include "config.h"
#if ENABLE(INSPECTOR)
#include "HeapGraphSerializer.h"
#include "InspectorValues.h"
#include "WebCoreMemoryInstrumentation.h"
#include <wtf/MemoryInstrumentationHashMap.h>
#include <wtf/MemoryInstrumentationVector.h>
#include <wtf/MemoryObjectInfo.h>
#include <wtf/text/CString.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
class HeapGraphNode {
public:
HeapGraphNode()
: m_type(0)
, m_size(0)
, m_className(0)
, m_name(0)
, m_edgeCount(0)
{
}
int m_type;
unsigned m_size;
int m_className;
int m_name;
int m_edgeCount;
static const int s_nodeFieldCount = 5;
};
class HeapGraphEdge {
public:
HeapGraphEdge()
: m_type(0)
, m_targetIndexIsKnown(false)
, m_toIndex(0)
, m_name(0)
{
}
int m_type;
bool m_targetIndexIsKnown;
union {
const void* m_toObject;
int m_toIndex;
};
int m_name;
};
HeapGraphSerializer::HeapGraphSerializer()
: m_lastReportedEdgeIndex(0)
{
m_strings.append(String());
memset(m_edgeTypes, 0, sizeof(m_edgeTypes));
ASSERT(m_strings.size());
m_edgeTypes[WTF::PointerMember] = m_strings.size();
m_strings.append("weakRef");
m_edgeTypes[WTF::OwnPtrMember] = m_strings.size();
m_strings.append("ownRef");
m_edgeTypes[WTF::RefPtrMember] = m_strings.size();
m_strings.append("countRef");
m_unknownClassNameId = addString("unknown");
}
HeapGraphSerializer::~HeapGraphSerializer()
{
}
void HeapGraphSerializer::reportNode(const WTF::MemoryObjectInfo& info)
{
HeapGraphNode node;
node.m_type = addString(info.objectType());
node.m_size = info.objectSize();
node.m_className = info.className().isEmpty() ? m_unknownClassNameId : addString(info.className());
node.m_name = addString(info.name());
// Node is always reported after its outgoing edges and leaves.
node.m_edgeCount = m_edges.size() - m_lastReportedEdgeIndex;
m_lastReportedEdgeIndex = m_edges.size();
m_objectToNodeIndex.set(info.reportedPointer(), m_nodes.size());
if (info.isRoot())
m_roots.append(info.reportedPointer());
m_nodes.append(node);
}
void HeapGraphSerializer::reportEdge(const void* to, const char* name, WTF::MemberType memberType)
{
HeapGraphEdge edge;
ASSERT(to);
ASSERT(memberType >= 0);
ASSERT(memberType < WTF::LastMemberTypeEntry);
edge.m_type = m_edgeTypes[memberType];
edge.m_toObject = to;
edge.m_name = addString(name);
m_edges.append(edge);
}
void HeapGraphSerializer::reportLeaf(const WTF::MemoryObjectInfo& info, const char* edgeName)
{
HeapGraphNode node;
node.m_type = addString(info.objectType());
node.m_size = info.objectSize();
node.m_className = addString(info.className());
node.m_name = addString(info.name());
int nodeIndex = m_nodes.size();
m_nodes.append(node);
HeapGraphEdge edge;
edge.m_type = m_edgeTypes[WTF::OwnPtrMember];
edge.m_toIndex = nodeIndex;
edge.m_targetIndexIsKnown = true;
edge.m_name = addString(edgeName);
m_edges.append(edge);
}
void HeapGraphSerializer::reportBaseAddress(const void* base, const void* real)
{
m_baseToRealAddress.set(base, real);
}
PassRefPtr<InspectorObject> HeapGraphSerializer::serialize()
{
addRootNode();
adjutEdgeTargets();
RefPtr<InspectorArray> nodes = InspectorArray::create();
for (size_t i = 0; i < m_nodes.size(); i++) {
HeapGraphNode& node = m_nodes[i];
nodes->pushInt(node.m_type);
nodes->pushInt(node.m_className);
nodes->pushInt(node.m_name);
nodes->pushInt(node.m_size);
nodes->pushInt(node.m_edgeCount);
}
RefPtr<InspectorArray> edges = InspectorArray::create();
for (size_t i = 0; i < m_edges.size(); i++) {
HeapGraphEdge& edge = m_edges[i];
edges->pushInt(edge.m_type);
edges->pushInt(edge.m_name);
edges->pushInt(edge.m_toIndex * HeapGraphNode::s_nodeFieldCount);
}
RefPtr<InspectorArray> strings = InspectorArray::create();
for (size_t i = 0; i < m_strings.size(); i++)
strings->pushString(m_strings[i]);
RefPtr<InspectorObject> graph = InspectorObject::create();
graph->setArray("nodes", nodes);
graph->setArray("edges", edges);
graph->setArray("strings", strings);
return graph.release();
}
void HeapGraphSerializer::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
{
MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Inspector);
info.addMember(m_stringToIndex, "stringToIndex");
info.addMember(m_strings, "strings");
info.addMember(m_objectToNodeIndex, "objectToNodeIndex");
info.addMember(m_baseToRealAddress, "baseToRealAddress");
info.addMember(m_nodes, "nodes");
info.addMember(m_edges, "edges");
info.addMember(m_roots, "roots");
}
int HeapGraphSerializer::addString(const String& string)
{
if (string.isEmpty())
return 0;
StringMap::AddResult result = m_stringToIndex.add(string, m_strings.size());
if (result.isNewEntry)
m_strings.append(string);
return result.iterator->value;
}
void HeapGraphSerializer::addRootNode()
{
for (size_t i = 0; i < m_roots.size(); i++)
reportEdge(m_roots[i], 0, WTF::PointerMember);
HeapGraphNode node;
node.m_name = addString("Root");
node.m_edgeCount = m_edges.size() - m_lastReportedEdgeIndex;
m_lastReportedEdgeIndex = m_edges.size();
m_nodes.append(node);
}
void HeapGraphSerializer::adjutEdgeTargets()
{
for (size_t i = 0; i < m_edges.size(); i++) {
HeapGraphEdge& edge = m_edges[i];
if (edge.m_targetIndexIsKnown)
continue;
const void* realTarget = m_baseToRealAddress.get(edge.m_toObject);
if (!realTarget)
realTarget = edge.m_toObject;
edge.m_toIndex = m_objectToNodeIndex.get(realTarget);
}
}
} // namespace WebCore
#endif // ENABLE(INSPECTOR)