blob: f159e05dcfa8907dc7af5251c29317d2605222f7 [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"
#include "core/inspector/HeapGraphSerializer.h"
#include "core/dom/WebCoreMemoryInstrumentation.h"
#include "core/inspector/JSONParser.h"
#include "wtf/MemoryInstrumentationHashMap.h"
#include "wtf/MemoryInstrumentationVector.h"
#include "wtf/MemoryObjectInfo.h"
#include "wtf/text/WTFString.h"
namespace WebCore {
HeapGraphSerializer::HeapGraphSerializer(Client* client)
: m_client(client)
, m_strings(Strings::create())
, m_edges(Edges::create())
, m_nodeEdgesCount(0)
, m_nodes(Nodes::create())
, m_baseToRealNodeIdMap(BaseToRealNodeIdMap::create())
, m_typeStrings(JSONObject::create())
, m_leafCount(0)
{
ASSERT(m_client);
m_strings->addItem(String()); // An empty string with 0 index.
memset(m_edgeTypes, 0, sizeof(m_edgeTypes));
m_edgeTypes[WTF::PointerMember] = registerTypeString("weak");
m_edgeTypes[WTF::RetainingPointer] = registerTypeString("property");
// FIXME: It is used as a magic constant for 'object' node type.
registerTypeString("object");
m_unknownClassNameId = registerString("unknown");
}
HeapGraphSerializer::~HeapGraphSerializer()
{
}
void HeapGraphSerializer::pushUpdateIfNeeded()
{
static const size_t chunkSize = 10000;
static const size_t averageEdgesPerNode = 5;
if (m_strings->length() <= chunkSize
&& m_nodes->length() <= chunkSize * s_nodeFieldsCount
&& m_edges->length() <= chunkSize * averageEdgesPerNode * s_edgeFieldsCount
&& m_baseToRealNodeIdMap->length() <= chunkSize * s_idMapEntryFieldCount)
return;
pushUpdate();
}
void HeapGraphSerializer::pushUpdate()
{
typedef TypeBuilder::Memory::HeapSnapshotChunk HeapSnapshotChunk;
RefPtr<HeapSnapshotChunk> chunk = HeapSnapshotChunk::create()
.setStrings(m_strings.release())
.setNodes(m_nodes.release())
.setEdges(m_edges.release())
.setBaseToRealNodeId(m_baseToRealNodeIdMap.release());
m_client->addNativeSnapshotChunk(chunk.release());
m_strings = Strings::create();
m_edges = Edges::create();
m_nodes = Nodes::create();
m_baseToRealNodeIdMap = BaseToRealNodeIdMap::create();
}
void HeapGraphSerializer::reportNode(const WTF::MemoryObjectInfo& info)
{
ASSERT(info.reportedPointer());
reportNodeImpl(info, m_nodeEdgesCount);
m_nodeEdgesCount = 0;
if (info.isRoot())
m_roots.append(info.reportedPointer());
pushUpdateIfNeeded();
}
int HeapGraphSerializer::reportNodeImpl(const WTF::MemoryObjectInfo& info, int edgesCount)
{
int nodeId = toNodeId(info.reportedPointer());
int classNameId = info.classNameId();
m_nodes->addItem(classNameId ? classNameId : m_unknownClassNameId);
m_nodes->addItem(info.nameId());
m_nodes->addItem(nodeId);
m_nodes->addItem(info.objectSize());
m_nodes->addItem(edgesCount);
return nodeId;
}
void HeapGraphSerializer::reportEdge(const void* to, const char* name, WTF::MemberType memberType)
{
ASSERT(to);
reportEdgeImpl(toNodeId(to), name, m_edgeTypes[memberType]);
pushUpdateIfNeeded();
}
void HeapGraphSerializer::reportEdgeImpl(const int toNodeId, const char* name, int memberType)
{
ASSERT(memberType >= 0);
ASSERT(memberType < WTF::LastMemberTypeEntry);
m_edges->addItem(memberType);
m_edges->addItem(registerString(name));
m_edges->addItem(toNodeId);
++m_nodeEdgesCount;
}
void HeapGraphSerializer::reportLeaf(const WTF::MemoryObjectInfo& info, const char* edgeName)
{
int nodeId = reportNodeImpl(info, 0);
reportEdgeImpl(nodeId, edgeName, m_edgeTypes[WTF::RetainingPointer]);
pushUpdateIfNeeded();
}
void HeapGraphSerializer::reportBaseAddress(const void* base, const void* real)
{
m_baseToRealNodeIdMap->addItem(toNodeId(base));
m_baseToRealNodeIdMap->addItem(toNodeId(real));
}
PassRefPtr<JSONObject> HeapGraphSerializer::finish()
{
addRootNode();
pushUpdate();
String metaString =
"{"
"\"node_fields\":["
"\"type\","
"\"name\","
"\"id\","
"\"self_size\","
"\"edge_count\""
"],"
"\"node_types\":["
"[]," // FIXME: It is a fallback for Heap Snapshot parser. In case of Native Heap Snapshot it is a plain string id.
"\"string\","
"\"number\","
"\"number\","
"\"number\""
"],"
"\"edge_fields\":["
"\"type\","
"\"name_or_index\","
"\"to_node\""
"],"
"\"edge_types\":["
"[],"
"\"string_or_number\","
"\"node\""
"]"
"}";
RefPtr<JSONValue> metaValue = parseJSON(metaString);
RefPtr<JSONObject> meta;
metaValue->asObject(&meta);
ASSERT(meta);
meta->setObject("type_strings", m_typeStrings);
return meta.release();
}
void HeapGraphSerializer::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
{
MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Inspector);
info.ignoreMember(m_stringToIndex);
info.ignoreMember(m_strings);
info.ignoreMember(m_edges);
info.ignoreMember(m_nodes);
info.ignoreMember(m_baseToRealNodeIdMap);
info.ignoreMember(m_roots);
}
int HeapGraphSerializer::registerString(const char* string)
{
if (!string)
return 0;
int length = strlen(string);
if (length > 256)
length = 256;
StringMap::AddResult result = m_stringToIndex.add(String(string, length), m_stringToIndex.size() + 1);
if (result.isNewEntry)
m_strings->addItem(string);
return result.iterator->value;
}
int HeapGraphSerializer::registerTypeString(const char* string)
{
int stringId = registerString(string);
m_typeStrings->setNumber(string, stringId);
return stringId;
}
int HeapGraphSerializer::toNodeId(const void* to)
{
if (!to)
return s_firstNodeId + m_address2NodeIdMap.size() + m_leafCount++;
Address2NodeId::AddResult result = m_address2NodeIdMap.add(to, s_firstNodeId + m_leafCount + m_address2NodeIdMap.size());
return result.iterator->value;
}
void HeapGraphSerializer::addRootNode()
{
for (size_t i = 0; i < m_roots.size(); i++)
reportEdgeImpl(toNodeId(m_roots[i]), 0, m_edgeTypes[WTF::PointerMember]);
m_nodes->addItem(registerString("Root"));
m_nodes->addItem(0);
m_nodes->addItem(s_firstNodeId + m_address2NodeIdMap.size() + m_leafCount);
m_nodes->addItem(0);
m_nodes->addItem(m_roots.size());
}
} // namespace WebCore