Commit 132af256 authored by alexeif@chromium.org's avatar alexeif@chromium.org

Split nodes and edges into separate arrays in heap profiler.

This allowed the following changes:
  - heap profiler now makes one pass less over the heap.
  - HeapEntriesMap does not allocate EntryInfo per each entry.
  - there's no need for an extra pass to set indexes before serialization.

As a result snapshot taking time has reduced up to 2x times.

Review URL: https://chromiumcodereview.appspot.com/10353010

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11531 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b28f403c
......@@ -6063,7 +6063,7 @@ const HeapGraphEdge* HeapGraphNode::GetChild(int index) const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::GetChild");
return reinterpret_cast<const HeapGraphEdge*>(
&ToInternal(this)->children()[index]);
ToInternal(this)->children()[index]);
}
......@@ -6157,7 +6157,7 @@ const HeapGraphNode* HeapSnapshot::GetNodeById(SnapshotObjectId id) const {
int HeapSnapshot::GetNodesCount() const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::GetNodesCount");
return ToInternal(this)->entries()->length();
return ToInternal(this)->entries().length();
}
......@@ -6165,7 +6165,7 @@ const HeapGraphNode* HeapSnapshot::GetNode(int index) const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::GetNode");
return reinterpret_cast<const HeapGraphNode*>(
ToInternal(this)->entries()->at(index));
&ToInternal(this)->entries().at(index));
}
......
......@@ -136,6 +136,14 @@ bool List<T, P>::RemoveElement(const T& elm) {
}
template<typename T, class P>
void List<T, P>::Allocate(int length) {
DeleteData(data_);
Initialize(length);
length_ = length;
}
template<typename T, class P>
void List<T, P>::Clear() {
DeleteData(data_);
......
......@@ -117,6 +117,9 @@ class List {
// pointer type. Returns the removed element.
INLINE(T RemoveLast()) { return Remove(length_ - 1); }
// Deletes current list contents and allocates space for 'length' elements.
INLINE(void Allocate(int length));
// Clears the list by setting the length to zero. Even if T is a
// pointer type, clearing the list doesn't delete the entries.
INLINE(void Clear());
......
......@@ -96,8 +96,51 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
HeapEntry* HeapGraphEdge::from() const {
return const_cast<HeapEntry*>(
reinterpret_cast<const HeapEntry*>(this - child_index_) - 1);
return &snapshot()->entries()[from_index_];
}
HeapSnapshot* HeapGraphEdge::snapshot() const {
return to_entry_->snapshot();
}
int HeapEntry::index() const {
return static_cast<int>(this - &snapshot_->entries().first());
}
int HeapEntry::set_children_index(int index) {
children_index_ = index;
int next_index = index + children_count_;
children_count_ = 0;
return next_index;
}
int HeapEntry::set_retainers_index(int index) {
retainers_index_ = index;
int next_index = index + retainers_count_;
retainers_count_ = 0;
return next_index;
}
HeapGraphEdge** HeapEntry::children_arr() {
ASSERT(children_index_ >= 0);
return &snapshot_->children()[children_index_];
}
HeapGraphEdge** HeapEntry::retainers_arr() {
ASSERT(retainers_index_ >= 0);
return &snapshot_->retainers()[retainers_index_];
}
HeapEntry* HeapEntry::dominator() const {
ASSERT(dominator_ >= 0);
return &snapshot_->entries()[dominator_];
}
......
......@@ -931,78 +931,72 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
}
void HeapGraphEdge::Init(
int child_index, Type type, const char* name, HeapEntry* to) {
HeapGraphEdge::HeapGraphEdge(
Type type, const char* name, int from, int to) :
type_(type),
from_index_(from),
to_index_(to),
name_(name) {
ASSERT(type == kContextVariable
|| type == kProperty
|| type == kInternal
|| type == kShortcut);
child_index_ = child_index;
type_ = type;
name_ = name;
to_ = to;
|| type == kProperty
|| type == kInternal
|| type == kShortcut);
}
void HeapGraphEdge::Init(int child_index, Type type, int index, HeapEntry* to) {
HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to) :
type_(type),
from_index_(from),
to_index_(to),
index_(index) {
ASSERT(type == kElement || type == kHidden || type == kWeak);
child_index_ = child_index;
type_ = type;
index_ = index;
to_ = to;
}
void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) {
Init(child_index, kElement, index, to);
void HeapGraphEdge::ReplaceToIndexWithEntry(HeapSnapshot* snapshot) {
to_entry_ = &snapshot->entries()[to_index_];
}
void HeapEntry::Init(HeapSnapshot* snapshot,
const int HeapEntry::kNoEntry = -1;
HeapEntry::HeapEntry(HeapSnapshot* snapshot,
Type type,
const char* name,
SnapshotObjectId id,
int self_size,
int children_count,
int retainers_count) {
snapshot_ = snapshot;
type_ = type;
painted_ = false;
user_reachable_ = false;
name_ = name;
self_size_ = self_size;
retained_size_ = 0;
entry_index_ = -1;
children_count_ = children_count;
retainers_count_ = retainers_count;
dominator_ = NULL;
id_ = id;
}
int self_size) :
painted_(false),
user_reachable_(false),
dominator_(kNoEntry),
type_(type),
retainers_count_(0),
retainers_index_(-1),
children_count_(0),
children_index_(-1),
self_size_(self_size),
retained_size_(0),
id_(id),
snapshot_(snapshot),
name_(name) { }
void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
int child_index,
const char* name,
HeapEntry* entry,
int retainer_index) {
children()[child_index].Init(child_index, type, name, entry);
entry->retainers()[retainer_index] = children_arr() + child_index;
HeapEntry* entry) {
HeapGraphEdge edge(type, name, this->index(), entry->index());
snapshot_->edges().Add(edge);
++children_count_;
++entry->retainers_count_;
}
void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
int child_index,
int index,
HeapEntry* entry,
int retainer_index) {
children()[child_index].Init(child_index, type, index, entry);
entry->retainers()[retainer_index] = children_arr() + child_index;
}
void HeapEntry::SetUnidirElementReference(
int child_index, int index, HeapEntry* entry) {
children()[child_index].Init(child_index, index, entry);
HeapEntry* entry) {
HeapGraphEdge edge(type, index, this->index(), entry->index());
snapshot_->edges().Add(edge);
++children_count_;
++entry->retainers_count_;
}
......@@ -1013,7 +1007,8 @@ Handle<HeapObject> HeapEntry::GetHeapObject() {
void HeapEntry::Print(
const char* prefix, const char* edge_name, int max_depth, int indent) {
OS::Print("%6d %7d @%6llu %*c %s%s: ",
STATIC_CHECK(sizeof(unsigned) == sizeof(id()));
OS::Print("%6d %7d @%6u %*c %s%s: ",
self_size(), retained_size(), id(),
indent, ' ', prefix, edge_name);
if (type() != kString) {
......@@ -1031,9 +1026,9 @@ void HeapEntry::Print(
OS::Print("\"\n");
}
if (--max_depth == 0) return;
Vector<HeapGraphEdge> ch = children();
Vector<HeapGraphEdge*> ch = children();
for (int i = 0; i < ch.length(); ++i) {
HeapGraphEdge& edge = ch[i];
HeapGraphEdge& edge = *ch[i];
const char* edge_prefix = "";
EmbeddedVector<char, 64> index;
const char* edge_name = index.start();
......@@ -1089,15 +1084,6 @@ const char* HeapEntry::TypeAsString() {
}
size_t HeapEntry::EntriesSize(int entries_count,
int children_count,
int retainers_count) {
return sizeof(HeapEntry) * entries_count // NOLINT
+ sizeof(HeapGraphEdge) * children_count // NOLINT
+ sizeof(HeapGraphEdge*) * retainers_count; // NOLINT
}
// It is very important to keep objects that form a heap snapshot
// as small as possible.
namespace { // Avoid littering the global namespace.
......@@ -1106,7 +1092,7 @@ template <size_t ptr_size> struct SnapshotSizeConstants;
template <> struct SnapshotSizeConstants<4> {
static const int kExpectedHeapGraphEdgeSize = 12;
static const int kExpectedHeapEntrySize = 36;
static const int kExpectedHeapEntrySize = 40;
static const size_t kMaxSerializableSnapshotRawSize = 256 * MB;
};
......@@ -1127,11 +1113,9 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
type_(type),
title_(title),
uid_(uid),
root_entry_(NULL),
gc_roots_entry_(NULL),
natives_root_entry_(NULL),
raw_entries_(NULL),
number_of_edges_(0),
root_index_(HeapEntry::kNoEntry),
gc_roots_index_(HeapEntry::kNoEntry),
natives_root_index_(HeapEntry::kNoEntry),
max_snapshot_js_object_id_(0) {
STATIC_CHECK(
sizeof(HeapGraphEdge) ==
......@@ -1140,16 +1124,11 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
sizeof(HeapEntry) ==
SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize);
for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) {
gc_subroot_entries_[i] = NULL;
gc_subroot_indexes_[i] = HeapEntry::kNoEntry;
}
}
HeapSnapshot::~HeapSnapshot() {
DeleteArray(raw_entries_);
}
void HeapSnapshot::Delete() {
collection_->RemoveSnapshot(this);
delete this;
......@@ -1161,19 +1140,8 @@ void HeapSnapshot::RememberLastJSObjectId() {
}
void HeapSnapshot::AllocateEntries(int entries_count,
int children_count,
int retainers_count) {
ASSERT(raw_entries_ == NULL);
number_of_edges_ = children_count;
raw_entries_size_ =
HeapEntry::EntriesSize(entries_count, children_count, retainers_count);
raw_entries_ = NewArray<char>(raw_entries_size_);
}
static void HeapEntryClearPaint(HeapEntry** entry_ptr) {
(*entry_ptr)->clear_paint();
static void HeapEntryClearPaint(HeapEntry* entry_ptr) {
entry_ptr->clear_paint();
}
......@@ -1182,76 +1150,80 @@ void HeapSnapshot::ClearPaint() {
}
HeapEntry* HeapSnapshot::AddRootEntry(int children_count) {
ASSERT(root_entry_ == NULL);
HeapEntry* HeapSnapshot::AddRootEntry() {
ASSERT(root_index_ == HeapEntry::kNoEntry);
ASSERT(entries_.is_empty()); // Root entry must be the first one.
return (root_entry_ = AddEntry(HeapEntry::kObject,
"",
HeapObjectsMap::kInternalRootObjectId,
0,
children_count,
0));
HeapEntry* entry = AddEntry(HeapEntry::kObject,
"",
HeapObjectsMap::kInternalRootObjectId,
0);
root_index_ = entry->index();
ASSERT(root_index_ == 0);
return entry;
}
HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count,
int retainers_count) {
ASSERT(gc_roots_entry_ == NULL);
return (gc_roots_entry_ = AddEntry(HeapEntry::kObject,
"(GC roots)",
HeapObjectsMap::kGcRootsObjectId,
0,
children_count,
retainers_count));
HeapEntry* HeapSnapshot::AddGcRootsEntry() {
ASSERT(gc_roots_index_ == HeapEntry::kNoEntry);
HeapEntry* entry = AddEntry(HeapEntry::kObject,
"(GC roots)",
HeapObjectsMap::kGcRootsObjectId,
0);
gc_roots_index_ = entry->index();
return entry;
}
HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag,
int children_count,
int retainers_count) {
ASSERT(gc_subroot_entries_[tag] == NULL);
HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag) {
ASSERT(gc_subroot_indexes_[tag] == HeapEntry::kNoEntry);
ASSERT(0 <= tag && tag < VisitorSynchronization::kNumberOfSyncTags);
return (gc_subroot_entries_[tag] = AddEntry(
HeapEntry* entry = AddEntry(
HeapEntry::kObject,
VisitorSynchronization::kTagNames[tag],
HeapObjectsMap::GetNthGcSubrootId(tag),
0,
children_count,
retainers_count));
0);
gc_subroot_indexes_[tag] = entry->index();
return entry;
}
HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
const char* name,
SnapshotObjectId id,
int size,
int children_count,
int retainers_count) {
HeapEntry* entry = GetNextEntryToInit();
entry->Init(this, type, name, id, size, children_count, retainers_count);
return entry;
int size) {
HeapEntry entry(this, type, name, id, size);
entries_.Add(entry);
return &entries_.last();
}
void HeapSnapshot::SetDominatorsToSelf() {
for (int i = 0; i < entries_.length(); ++i) {
HeapEntry* entry = entries_[i];
if (entry->dominator() == NULL) entry->set_dominator(entry);
void HeapSnapshot::FillChildrenAndRetainers() {
ASSERT(children().is_empty());
children().Allocate(edges().length());
ASSERT(retainers().is_empty());
retainers().Allocate(edges().length());
int children_index = 0;
int retainers_index = 0;
for (int i = 0; i < entries().length(); ++i) {
HeapEntry* entry = &entries()[i];
children_index = entry->set_children_index(children_index);
retainers_index = entry->set_retainers_index(retainers_index);
}
ASSERT(edges().length() == children_index);
ASSERT(edges().length() == retainers_index);
for (int i = 0; i < edges().length(); ++i) {
HeapGraphEdge* edge = &edges()[i];
edge->ReplaceToIndexWithEntry(this);
edge->from()->add_child(edge);
edge->to()->add_retainer(edge);
}
}
HeapEntry* HeapSnapshot::GetNextEntryToInit() {
if (entries_.length() > 0) {
HeapEntry* last_entry = entries_.last();
entries_.Add(reinterpret_cast<HeapEntry*>(
reinterpret_cast<char*>(last_entry) + last_entry->EntrySize()));
} else {
entries_.Add(reinterpret_cast<HeapEntry*>(raw_entries_));
void HeapSnapshot::SetDominatorsToSelf() {
for (int i = 0; i < entries_.length(); ++i) {
entries_[i].set_dominator(&entries_[i]);
}
ASSERT(reinterpret_cast<char*>(entries_.last()) <
(raw_entries_ + raw_entries_size_));
return entries_.last();
}
......@@ -1287,7 +1259,10 @@ static int SortByIds(const T* entry1_ptr,
List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() {
if (sorted_entries_.is_empty()) {
sorted_entries_.AddAll(entries_);
sorted_entries_.Allocate(entries_.length());
for (int i = 0; i < entries_.length(); ++i) {
sorted_entries_[i] = &entries_[i];
}
sorted_entries_.Sort(SortByIds);
}
return &sorted_entries_;
......@@ -1299,6 +1274,22 @@ void HeapSnapshot::Print(int max_depth) {
}
template<typename T, class P>
static size_t GetMemoryUsedByList(const List<T,P>& list) {
return list.capacity() * sizeof(T);
}
size_t HeapSnapshot::RawSnapshotSize() const {
return
GetMemoryUsedByList(entries_) +
GetMemoryUsedByList(edges_) +
GetMemoryUsedByList(children_) +
GetMemoryUsedByList(retainers_) +
GetMemoryUsedByList(sorted_entries_);
}
// We split IDs on evens for embedder objects (see
// HeapObjectsMap::GenerateId) and odds for native objects.
const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = 1;
......@@ -1567,99 +1558,22 @@ Handle<HeapObject> HeapSnapshotsCollection::FindHeapObjectById(
}
HeapEntry* const HeapEntriesMap::kHeapEntryPlaceholder =
reinterpret_cast<HeapEntry*>(1);
HeapEntriesMap::HeapEntriesMap()
: entries_(HeapThingsMatch),
entries_count_(0),
total_children_count_(0),
total_retainers_count_(0) {
}
HeapEntriesMap::~HeapEntriesMap() {
for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) {
delete reinterpret_cast<EntryInfo*>(p->value);
}
}
void HeapEntriesMap::AllocateHeapEntryForMapEntry(HashMap::Entry* map_entry) {
EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(map_entry->value);
entry_info->entry = entry_info->allocator->AllocateEntry(
map_entry->key,
entry_info->children_count,
entry_info->retainers_count);
ASSERT(entry_info->entry != NULL);
ASSERT(entry_info->entry != kHeapEntryPlaceholder);
entry_info->children_count = 0;
entry_info->retainers_count = 0;
}
void HeapEntriesMap::AllocateEntries(HeapThing root_object) {
HashMap::Entry* root_entry =
entries_.Lookup(root_object, Hash(root_object), false);
ASSERT(root_entry != NULL);
// Make sure root entry is allocated first.
AllocateHeapEntryForMapEntry(root_entry);
void* root_entry_value = root_entry->value;
// Remove the root object from map while iterating through other entries.
entries_.Remove(root_object, Hash(root_object));
root_entry = NULL;
for (HashMap::Entry* p = entries_.Start();
p != NULL;
p = entries_.Next(p)) {
AllocateHeapEntryForMapEntry(p);
}
// Insert root entry back.
root_entry = entries_.Lookup(root_object, Hash(root_object), true);
root_entry->value = root_entry_value;
: entries_(HeapThingsMatch) {
}
HeapEntry* HeapEntriesMap::Map(HeapThing thing) {
int HeapEntriesMap::Map(HeapThing thing) {
HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), false);
if (cache_entry != NULL) {
EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value);
return entry_info->entry;
} else {
return NULL;
}
if (cache_entry == NULL) return HeapEntry::kNoEntry;
return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value));
}
void HeapEntriesMap::Pair(
HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry) {
void HeapEntriesMap::Pair(HeapThing thing, int entry) {
HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), true);
ASSERT(cache_entry->value == NULL);
cache_entry->value = new EntryInfo(entry, allocator);
++entries_count_;
}
void HeapEntriesMap::CountReference(HeapThing from, HeapThing to,
int* prev_children_count,
int* prev_retainers_count) {
HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), false);
HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false);
ASSERT(from_cache_entry != NULL);
ASSERT(to_cache_entry != NULL);
EntryInfo* from_entry_info =
reinterpret_cast<EntryInfo*>(from_cache_entry->value);
EntryInfo* to_entry_info =
reinterpret_cast<EntryInfo*>(to_cache_entry->value);
if (prev_children_count)
*prev_children_count = from_entry_info->children_count;
if (prev_retainers_count)
*prev_retainers_count = to_entry_info->retainers_count;
++from_entry_info->children_count;
++to_entry_info->retainers_count;
++total_children_count_;
++total_retainers_count_;
cache_entry->value = reinterpret_cast<void*>(static_cast<intptr_t>(entry));
}
......@@ -1676,20 +1590,14 @@ void HeapObjectsSet::Clear() {
bool HeapObjectsSet::Contains(Object* obj) {
if (!obj->IsHeapObject()) return false;
HeapObject* object = HeapObject::cast(obj);
HashMap::Entry* cache_entry =
entries_.Lookup(object, HeapEntriesMap::Hash(object), false);
return cache_entry != NULL;
return entries_.Lookup(object, HeapEntriesMap::Hash(object), false) != NULL;
}
void HeapObjectsSet::Insert(Object* obj) {
if (!obj->IsHeapObject()) return;
HeapObject* object = HeapObject::cast(obj);
HashMap::Entry* cache_entry =
entries_.Lookup(object, HeapEntriesMap::Hash(object), true);
if (cache_entry->value == NULL) {
cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder;
}
entries_.Lookup(object, HeapEntriesMap::Hash(object), true);
}
......@@ -1697,12 +1605,9 @@ const char* HeapObjectsSet::GetTag(Object* obj) {
HeapObject* object = HeapObject::cast(obj);
HashMap::Entry* cache_entry =
entries_.Lookup(object, HeapEntriesMap::Hash(object), false);
if (cache_entry != NULL
&& cache_entry->value != HeapEntriesMap::kHeapEntryPlaceholder) {
return reinterpret_cast<const char*>(cache_entry->value);
} else {
return NULL;
}
return cache_entry != NULL
? reinterpret_cast<const char*>(cache_entry->value)
: NULL;
}
......@@ -1744,129 +1649,76 @@ V8HeapExplorer::~V8HeapExplorer() {
}
HeapEntry* V8HeapExplorer::AllocateEntry(
HeapThing ptr, int children_count, int retainers_count) {
return AddEntry(
reinterpret_cast<HeapObject*>(ptr), children_count, retainers_count);
HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) {
return AddEntry(reinterpret_cast<HeapObject*>(ptr));
}
HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
int children_count,
int retainers_count) {
HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) {
if (object == kInternalRootObject) {
ASSERT(retainers_count == 0);
return snapshot_->AddRootEntry(children_count);
snapshot_->AddRootEntry();
return snapshot_->root();
} else if (object == kGcRootsObject) {
return snapshot_->AddGcRootsEntry(children_count, retainers_count);
HeapEntry* entry = snapshot_->AddGcRootsEntry();
return entry;
} else if (object >= kFirstGcSubrootObject && object < kLastGcSubrootObject) {
return snapshot_->AddGcSubrootEntry(
GetGcSubrootOrder(object),
children_count,
retainers_count);
HeapEntry* entry = snapshot_->AddGcSubrootEntry(GetGcSubrootOrder(object));
return entry;
} else if (object->IsJSFunction()) {
JSFunction* func = JSFunction::cast(object);
SharedFunctionInfo* shared = func->shared();
const char* name = shared->bound() ? "native_bind" :
collection_->names()->GetName(String::cast(shared->name()));
return AddEntry(object,
HeapEntry::kClosure,
name,
children_count,
retainers_count);
return AddEntry(object, HeapEntry::kClosure, name);
} else if (object->IsJSRegExp()) {
JSRegExp* re = JSRegExp::cast(object);
return AddEntry(object,
HeapEntry::kRegExp,
collection_->names()->GetName(re->Pattern()),
children_count,
retainers_count);
collection_->names()->GetName(re->Pattern()));
} else if (object->IsJSObject()) {
return AddEntry(object,
HeapEntry::kObject,
"",
children_count,
retainers_count);
return AddEntry(object, HeapEntry::kObject, "");
} else if (object->IsString()) {
return AddEntry(object,
HeapEntry::kString,
collection_->names()->GetName(String::cast(object)),
children_count,
retainers_count);
collection_->names()->GetName(String::cast(object)));
} else if (object->IsCode()) {
return AddEntry(object,
HeapEntry::kCode,
"",
children_count,
retainers_count);
return AddEntry(object, HeapEntry::kCode, "");
} else if (object->IsSharedFunctionInfo()) {
SharedFunctionInfo* shared = SharedFunctionInfo::cast(object);
String* name = String::cast(SharedFunctionInfo::cast(object)->name());
return AddEntry(object,
HeapEntry::kCode,
collection_->names()->GetName(String::cast(shared->name())),
children_count,
retainers_count);
collection_->names()->GetName(name));
} else if (object->IsScript()) {
Script* script = Script::cast(object);
Object* name = Script::cast(object)->name();
return AddEntry(object,
HeapEntry::kCode,
script->name()->IsString() ?
collection_->names()->GetName(
String::cast(script->name()))
: "",
children_count,
retainers_count);
name->IsString()
? collection_->names()->GetName(String::cast(name))
: "");
} else if (object->IsGlobalContext()) {
return AddEntry(object,
HeapEntry::kHidden,
"system / GlobalContext",
children_count,
retainers_count);
return AddEntry(object, HeapEntry::kHidden, "system / GlobalContext");
} else if (object->IsContext()) {
return AddEntry(object,
HeapEntry::kHidden,
"system / Context",
children_count,
retainers_count);
return AddEntry(object, HeapEntry::kHidden, "system / Context");
} else if (object->IsFixedArray() ||
object->IsFixedDoubleArray() ||
object->IsByteArray() ||
object->IsExternalArray()) {
const char* tag = objects_tags_.GetTag(object);
return AddEntry(object,
HeapEntry::kArray,
tag != NULL ? tag : "",
children_count,
retainers_count);
return AddEntry(object, HeapEntry::kArray, tag != NULL ? tag : "");
} else if (object->IsHeapNumber()) {
return AddEntry(object,
HeapEntry::kHeapNumber,
"number",
children_count,
retainers_count);
return AddEntry(object, HeapEntry::kHeapNumber, "number");
}
return AddEntry(object,
HeapEntry::kHidden,
GetSystemEntryName(object),
children_count,
retainers_count);
return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object));
}
HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
HeapEntry::Type type,
const char* name,
int children_count,
int retainers_count) {
const char* name) {
int object_size = object->Size();
SnapshotObjectId object_id =
collection_->GetObjectId(object->address(), object_size);
return snapshot_->AddEntry(type,
name,
object_id,
object_size,
children_count,
retainers_count);
return snapshot_->AddEntry(type, name, object_id, object_size);
}
......@@ -1935,10 +1787,10 @@ class IndexedReferencesExtractor : public ObjectVisitor {
public:
IndexedReferencesExtractor(V8HeapExplorer* generator,
HeapObject* parent_obj,
HeapEntry* parent_entry)
int parent)
: generator_(generator),
parent_obj_(parent_obj),
parent_(parent_entry),
parent_(parent),
next_index_(1) {
}
void VisitPointers(Object** start, Object** end) {
......@@ -1967,14 +1819,15 @@ class IndexedReferencesExtractor : public ObjectVisitor {
}
V8HeapExplorer* generator_;
HeapObject* parent_obj_;
HeapEntry* parent_;
int parent_;
int next_index_;
};
void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
HeapEntry* entry = GetEntry(obj);
if (entry == NULL) return; // No interest in this object.
HeapEntry* heap_entry = GetEntry(obj);
if (heap_entry == NULL) return; // No interest in this object.
int entry = heap_entry->index();
bool extract_indexed_refs = true;
if (obj->IsJSGlobalProxy()) {
......@@ -2026,7 +1879,7 @@ void V8HeapExplorer::ExtractJSGlobalProxyReferences(JSGlobalProxy* proxy) {
void V8HeapExplorer::ExtractJSObjectReferences(
HeapEntry* entry, JSObject* js_obj) {
int entry, JSObject* js_obj) {
HeapObject* obj = js_obj;
ExtractClosureReferences(js_obj, entry);
ExtractPropertyReferences(js_obj, entry);
......@@ -2095,7 +1948,7 @@ void V8HeapExplorer::ExtractJSObjectReferences(
}
void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, String* string) {
void V8HeapExplorer::ExtractStringReferences(int entry, String* string) {
if (string->IsConsString()) {
ConsString* cs = ConsString::cast(string);
SetInternalReference(cs, entry, "first", cs->first());
......@@ -2107,8 +1960,7 @@ void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, String* string) {
}
void V8HeapExplorer::ExtractContextReferences(
HeapEntry* entry, Context* context) {
void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
#define EXTRACT_CONTEXT_FIELD(index, type, name) \
SetInternalReference(context, entry, #name, context->get(Context::index), \
FixedArray::OffsetOfElementAt(Context::index));
......@@ -2134,7 +1986,7 @@ void V8HeapExplorer::ExtractContextReferences(
}
void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) {
void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
SetInternalReference(map, entry,
"prototype", map->prototype(), Map::kPrototypeOffset);
SetInternalReference(map, entry,
......@@ -2163,7 +2015,7 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) {
void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
HeapEntry* entry, SharedFunctionInfo* shared) {
int entry, SharedFunctionInfo* shared) {
HeapObject* obj = shared;
SetInternalReference(obj, entry,
"name", shared->name(),
......@@ -2205,7 +2057,7 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
}
void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) {
void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) {
HeapObject* obj = script;
SetInternalReference(obj, entry,
"source", script->source(),
......@@ -2227,7 +2079,7 @@ void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) {
void V8HeapExplorer::ExtractCodeCacheReferences(
HeapEntry* entry, CodeCache* code_cache) {
int entry, CodeCache* code_cache) {
TagObject(code_cache->default_cache(), "(default code cache)");
SetInternalReference(code_cache, entry,
"default_cache", code_cache->default_cache(),
......@@ -2239,7 +2091,7 @@ void V8HeapExplorer::ExtractCodeCacheReferences(
}
void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code* code) {
void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) {
TagObject(code->relocation_info(), "(code relocation info)");
SetInternalReference(code, entry,
"relocation_info", code->relocation_info(),
......@@ -2261,13 +2113,12 @@ void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code* code) {
void V8HeapExplorer::ExtractJSGlobalPropertyCellReferences(
HeapEntry* entry, JSGlobalPropertyCell* cell) {
int entry, JSGlobalPropertyCell* cell) {
SetInternalReference(cell, entry, "value", cell->value());
}
void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj,
HeapEntry* entry) {
void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) {
if (!js_obj->IsJSFunction()) return;
JSFunction* func = JSFunction::cast(js_obj);
......@@ -2309,8 +2160,7 @@ void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj,
}
void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
HeapEntry* entry) {
void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
if (js_obj->HasFastProperties()) {
DescriptorArray* descs = js_obj->map()->instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
......@@ -2383,8 +2233,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
}
void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj,
HeapEntry* entry) {
void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) {
if (js_obj->HasFastElements()) {
FixedArray* elements = FixedArray::cast(js_obj->elements());
int length = js_obj->IsJSArray() ?
......@@ -2410,8 +2259,7 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj,
}
void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj,
HeapEntry* entry) {
void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, int entry) {
int length = js_obj->GetInternalFieldCount();
for (int i = 0; i < length; ++i) {
Object* o = js_obj->GetInternalField(i);
......@@ -2537,6 +2385,7 @@ bool V8HeapExplorer::IterateAndExtractReferences(
filler_ = NULL;
return false;
}
SetRootGcRootsReference();
RootsReferencesExtractor extractor;
heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG);
......@@ -2544,7 +2393,7 @@ bool V8HeapExplorer::IterateAndExtractReferences(
heap_->IterateRoots(&extractor, VISIT_ALL);
extractor.FillReferences(this);
filler_ = NULL;
return progress_->ProgressReport(false);
return progress_->ProgressReport(true);
}
......@@ -2592,55 +2441,49 @@ bool V8HeapExplorer::IsEssentialObject(Object* object) {
void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int parent_entry,
String* reference_name,
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kContextVariable,
parent_obj,
parent_entry,
collection_->names()->GetName(reference_name),
child_obj,
child_entry);
}
}
void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int parent_entry,
const char* reference_name,
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kShortcut,
parent_obj,
parent_entry,
reference_name,
child_obj,
child_entry);
}
}
void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int parent_entry,
int index,
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetIndexedReference(HeapGraphEdge::kElement,
parent_obj,
parent_entry,
index,
child_obj,
child_entry);
}
}
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int parent_entry,
const char* reference_name,
Object* child_obj,
int field_offset) {
......@@ -2648,16 +2491,16 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
if (child_entry == NULL) return;
if (IsEssentialObject(child_obj)) {
filler_->SetNamedReference(HeapGraphEdge::kInternal,
parent_obj, parent_entry,
parent_entry,
reference_name,
child_obj, child_entry);
child_entry);
}
IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int parent_entry,
int index,
Object* child_obj,
int field_offset) {
......@@ -2665,42 +2508,38 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
if (child_entry == NULL) return;
if (IsEssentialObject(child_obj)) {
filler_->SetNamedReference(HeapGraphEdge::kInternal,
parent_obj, parent_entry,
parent_entry,
collection_->names()->GetName(index),
child_obj, child_entry);
child_entry);
}
IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int parent_entry,
int index,
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL && IsEssentialObject(child_obj)) {
filler_->SetIndexedReference(HeapGraphEdge::kHidden,
parent_obj,
parent_entry,
index,
child_obj,
child_entry);
}
}
void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int parent_entry,
int index,
Object* child_obj,
int field_offset) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetIndexedReference(HeapGraphEdge::kWeak,
parent_obj,
parent_entry,
index,
child_obj,
child_entry);
IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
......@@ -2708,7 +2547,7 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int parent_entry,
String* reference_name,
Object* child_obj,
const char* name_format_string,
......@@ -2725,10 +2564,8 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
collection_->names()->GetName(reference_name);
filler_->SetNamedReference(type,
parent_obj,
parent_entry,
name,
child_obj,
child_entry);
IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
......@@ -2736,16 +2573,14 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int parent_entry,
String* reference_name,
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kShortcut,
parent_obj,
parent_entry,
collection_->names()->GetName(reference_name),
child_obj,
child_entry);
}
}
......@@ -2754,8 +2589,8 @@ void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj,
void V8HeapExplorer::SetRootGcRootsReference() {
filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement,
kInternalRootObject, snapshot_->root(),
kGcRootsObject, snapshot_->gc_roots());
snapshot_->root()->index(),
snapshot_->gc_roots());
}
......@@ -2764,16 +2599,16 @@ void V8HeapExplorer::SetUserGlobalReference(Object* child_obj) {
ASSERT(child_entry != NULL);
filler_->SetNamedAutoIndexReference(
HeapGraphEdge::kShortcut,
kInternalRootObject, snapshot_->root(),
child_obj, child_entry);
snapshot_->root()->index(),
child_entry);
}
void V8HeapExplorer::SetGcRootsReference(VisitorSynchronization::SyncTag tag) {
filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement,
kGcRootsObject, snapshot_->gc_roots(),
GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag));
snapshot_->gc_roots()->index(),
snapshot_->gc_subroot(tag));
}
......@@ -2785,14 +2620,14 @@ void V8HeapExplorer::SetGcSubrootReference(
if (name != NULL) {
filler_->SetNamedReference(
HeapGraphEdge::kInternal,
GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag),
snapshot_->gc_subroot(tag)->index(),
name,
child_obj, child_entry);
child_entry);
} else {
filler_->SetIndexedAutoIndexReference(
is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kElement,
GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag),
child_obj, child_entry);
snapshot_->gc_subroot(tag)->index(),
child_entry);
}
}
}
......@@ -2909,8 +2744,7 @@ class BasicHeapEntriesAllocator : public HeapEntriesAllocator {
collection_(snapshot_->collection()),
entries_type_(entries_type) {
}
virtual HeapEntry* AllocateEntry(
HeapThing ptr, int children_count, int retainers_count);
virtual HeapEntry* AllocateEntry(HeapThing ptr);
private:
HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_;
......@@ -2918,23 +2752,19 @@ class BasicHeapEntriesAllocator : public HeapEntriesAllocator {
};
HeapEntry* BasicHeapEntriesAllocator::AllocateEntry(
HeapThing ptr, int children_count, int retainers_count) {
HeapEntry* BasicHeapEntriesAllocator::AllocateEntry(HeapThing ptr) {
v8::RetainedObjectInfo* info = reinterpret_cast<v8::RetainedObjectInfo*>(ptr);
intptr_t elements = info->GetElementCount();
intptr_t size = info->GetSizeInBytes();
const char* name = elements != -1
? collection_->names()->GetFormatted(
"%s / %" V8_PTR_PREFIX "d entries", info->GetLabel(), elements)
: collection_->names()->GetCopy(info->GetLabel());
return snapshot_->AddEntry(
entries_type_,
elements != -1 ?
collection_->names()->GetFormatted(
"%s / %" V8_PTR_PREFIX "d entries",
info->GetLabel(),
info->GetElementCount()) :
collection_->names()->GetCopy(info->GetLabel()),
name,
HeapObjectsMap::GenerateId(info),
size != -1 ? static_cast<int>(size) : 0,
children_count,
retainers_count);
size != -1 ? static_cast<int>(size) : 0);
}
......@@ -3015,9 +2845,9 @@ void NativeObjectsExplorer::FillImplicitReferences() {
for (int i = 0; i < groups->length(); ++i) {
ImplicitRefGroup* group = groups->at(i);
HeapObject* parent = *group->parent_;
HeapEntry* parent_entry =
filler_->FindOrAddEntry(parent, native_entries_allocator_);
ASSERT(parent_entry != NULL);
int parent_entry =
filler_->FindOrAddEntry(parent, native_entries_allocator_)->index();
ASSERT(parent_entry != HeapEntry::kNoEntry);
Object*** children = group->children_;
for (size_t j = 0; j < group->length_; ++j) {
Object* child = *children[j];
......@@ -3025,9 +2855,9 @@ void NativeObjectsExplorer::FillImplicitReferences() {
filler_->FindOrAddEntry(child, native_entries_allocator_);
filler_->SetNamedReference(
HeapGraphEdge::kInternal,
parent, parent_entry,
parent_entry,
"native",
child, child_entry);
child_entry);
}
}
}
......@@ -3105,8 +2935,9 @@ NativeGroupRetainedObjectInfo* NativeObjectsExplorer::FindOrAddGroupInfo(
HEAP->HashSeed());
HashMap::Entry* entry = native_groups_.Lookup(const_cast<char*>(label_copy),
hash, true);
if (entry->value == NULL)
if (entry->value == NULL) {
entry->value = new NativeGroupRetainedObjectInfo(label);
}
return static_cast<NativeGroupRetainedObjectInfo*>(entry->value);
}
......@@ -3122,8 +2953,8 @@ void NativeObjectsExplorer::SetNativeRootReference(
filler_->FindOrAddEntry(group_info, synthetic_entries_allocator_);
filler_->SetNamedAutoIndexReference(
HeapGraphEdge::kInternal,
group_info, group_entry,
info, child_entry);
group_entry->index(),
child_entry);
}
......@@ -3135,12 +2966,12 @@ void NativeObjectsExplorer::SetWrapperNativeReferences(
filler_->FindOrAddEntry(info, native_entries_allocator_);
ASSERT(info_entry != NULL);
filler_->SetNamedReference(HeapGraphEdge::kInternal,
wrapper, wrapper_entry,
wrapper_entry->index(),
"native",
info, info_entry);
info_entry);
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
info, info_entry,
wrapper, wrapper_entry);
info_entry->index(),
wrapper_entry);
}
......@@ -3155,8 +2986,8 @@ void NativeObjectsExplorer::SetRootNativeRootsReference() {
ASSERT(group_entry != NULL);
filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement,
V8HeapExplorer::kInternalRootObject, snapshot_->root(),
group_info, group_entry);
snapshot_->root()->index(),
group_entry);
}
}
......@@ -3171,56 +3002,6 @@ void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) {
}
class SnapshotCounter : public SnapshotFillerInterface {
public:
explicit SnapshotCounter(HeapEntriesMap* entries) : entries_(entries) { }
HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
entries_->Pair(ptr, allocator, HeapEntriesMap::kHeapEntryPlaceholder);
return HeapEntriesMap::kHeapEntryPlaceholder;
}
HeapEntry* FindEntry(HeapThing ptr) {
return entries_->Map(ptr);
}
HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
HeapEntry* entry = FindEntry(ptr);
return entry != NULL ? entry : AddEntry(ptr, allocator);
}
void SetIndexedReference(HeapGraphEdge::Type,
HeapThing parent_ptr,
HeapEntry*,
int,
HeapThing child_ptr,
HeapEntry*) {
entries_->CountReference(parent_ptr, child_ptr);
}
void SetIndexedAutoIndexReference(HeapGraphEdge::Type,
HeapThing parent_ptr,
HeapEntry*,
HeapThing child_ptr,
HeapEntry*) {
entries_->CountReference(parent_ptr, child_ptr);
}
void SetNamedReference(HeapGraphEdge::Type,
HeapThing parent_ptr,
HeapEntry*,
const char*,
HeapThing child_ptr,
HeapEntry*) {
entries_->CountReference(parent_ptr, child_ptr);
}
void SetNamedAutoIndexReference(HeapGraphEdge::Type,
HeapThing parent_ptr,
HeapEntry*,
HeapThing child_ptr,
HeapEntry*) {
entries_->CountReference(parent_ptr, child_ptr);
}
private:
HeapEntriesMap* entries_;
};
class SnapshotFiller : public SnapshotFillerInterface {
public:
explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries)
......@@ -3228,64 +3009,48 @@ class SnapshotFiller : public SnapshotFillerInterface {
collection_(snapshot->collection()),
entries_(entries) { }
HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
UNREACHABLE();
return NULL;
HeapEntry* entry = allocator->AllocateEntry(ptr);
entries_->Pair(ptr, entry->index());
return entry;
}
HeapEntry* FindEntry(HeapThing ptr) {
return entries_->Map(ptr);
int index = entries_->Map(ptr);
return index != HeapEntry::kNoEntry ? &snapshot_->entries()[index] : NULL;
}
HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
HeapEntry* entry = FindEntry(ptr);
return entry != NULL ? entry : AddEntry(ptr, allocator);
}
void SetIndexedReference(HeapGraphEdge::Type type,
HeapThing parent_ptr,
HeapEntry* parent_entry,
int parent,
int index,
HeapThing child_ptr,
HeapEntry* child_entry) {
int child_index, retainer_index;
entries_->CountReference(
parent_ptr, child_ptr, &child_index, &retainer_index);
parent_entry->SetIndexedReference(
type, child_index, index, child_entry, retainer_index);
HeapEntry* parent_entry = &snapshot_->entries()[parent];
parent_entry->SetIndexedReference(type, index, child_entry);
}
void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
HeapThing parent_ptr,
HeapEntry* parent_entry,
HeapThing child_ptr,
int parent,
HeapEntry* child_entry) {
int child_index, retainer_index;
entries_->CountReference(
parent_ptr, child_ptr, &child_index, &retainer_index);
parent_entry->SetIndexedReference(
type, child_index, child_index + 1, child_entry, retainer_index);
HeapEntry* parent_entry = &snapshot_->entries()[parent];
int index = parent_entry->children_count() + 1;
parent_entry->SetIndexedReference(type, index, child_entry);
}
void SetNamedReference(HeapGraphEdge::Type type,
HeapThing parent_ptr,
HeapEntry* parent_entry,
int parent,
const char* reference_name,
HeapThing child_ptr,
HeapEntry* child_entry) {
int child_index, retainer_index;
entries_->CountReference(
parent_ptr, child_ptr, &child_index, &retainer_index);
parent_entry->SetNamedReference(
type, child_index, reference_name, child_entry, retainer_index);
HeapEntry* parent_entry = &snapshot_->entries()[parent];
parent_entry->SetNamedReference(type, reference_name, child_entry);
}
void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
HeapThing parent_ptr,
HeapEntry* parent_entry,
HeapThing child_ptr,
int parent,
HeapEntry* child_entry) {
int child_index, retainer_index;
entries_->CountReference(
parent_ptr, child_ptr, &child_index, &retainer_index);
parent_entry->SetNamedReference(type,
child_index,
collection_->names()->GetName(child_index + 1),
child_entry,
retainer_index);
HeapEntry* parent_entry = &snapshot_->entries()[parent];
int index = parent_entry->children_count() + 1;
parent_entry->SetNamedReference(
type,
collection_->names()->GetName(index),
child_entry);
}
private:
......@@ -3335,30 +3100,15 @@ bool HeapSnapshotGenerator::GenerateSnapshot() {
debug_heap->Verify();
#endif
SetProgressTotal(2); // 2 passes.
#ifdef DEBUG
debug_heap->Verify();
#endif
// Pass 1. Iterate heap contents to count entries and references.
if (!CountEntriesAndReferences()) return false;
SetProgressTotal(1); // 1 pass.
#ifdef DEBUG
debug_heap->Verify();
#endif
// Allocate memory for entries and references.
snapshot_->AllocateEntries(entries_.entries_count(),
entries_.total_children_count(),
entries_.total_retainers_count());
// Allocate heap objects to entries hash map.
entries_.AllocateEntries(V8HeapExplorer::kInternalRootObject);
// Pass 2. Fill references.
if (!FillReferences()) return false;
snapshot_->FillChildrenAndRetainers();
snapshot_->RememberLastJSObjectId();
if (!SetEntriesDominators()) return false;
......@@ -3390,23 +3140,16 @@ bool HeapSnapshotGenerator::ProgressReport(bool force) {
void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
if (control_ == NULL) return;
HeapIterator iterator(HeapIterator::kFilterUnreachable);
progress_total_ = (
progress_total_ = iterations_count * (
v8_heap_explorer_.EstimateObjectsCount(&iterator) +
dom_explorer_.EstimateObjectsCount()) * iterations_count;
dom_explorer_.EstimateObjectsCount());
progress_counter_ = 0;
}
bool HeapSnapshotGenerator::CountEntriesAndReferences() {
SnapshotCounter counter(&entries_);
v8_heap_explorer_.AddRootEntries(&counter);
return v8_heap_explorer_.IterateAndExtractReferences(&counter)
&& dom_explorer_.IterateAndExtractReferences(&counter);
}
bool HeapSnapshotGenerator::FillReferences() {
SnapshotFiller filler(snapshot_, &entries_);
v8_heap_explorer_.AddRootEntries(&filler);
// IterateAndExtractReferences cannot set object names because
// it makes call to JSObject::LocalLookupRealNamedProperty which
// in turn may relocate objects in property maps thus changing the heap
......@@ -3419,19 +3162,19 @@ bool HeapSnapshotGenerator::FillReferences() {
}
bool HeapSnapshotGenerator::IsUserGlobalReference(const HeapGraphEdge& edge) {
ASSERT(edge.from() == snapshot_->root());
return edge.type() == HeapGraphEdge::kShortcut;
bool HeapSnapshotGenerator::IsUserGlobalReference(const HeapGraphEdge* edge) {
ASSERT(edge->from() == snapshot_->root());
return edge->type() == HeapGraphEdge::kShortcut;
}
void HeapSnapshotGenerator::MarkUserReachableObjects() {
List<HeapEntry*> worklist;
Vector<HeapGraphEdge> children = snapshot_->root()->children();
Vector<HeapGraphEdge*> children = snapshot_->root()->children();
for (int i = 0; i < children.length(); ++i) {
if (IsUserGlobalReference(children[i])) {
worklist.Add(children[i].to());
worklist.Add(children[i]->to());
}
}
......@@ -3439,9 +3182,9 @@ void HeapSnapshotGenerator::MarkUserReachableObjects() {
HeapEntry* entry = worklist.RemoveLast();
if (entry->user_reachable()) continue;
entry->set_user_reachable();
Vector<HeapGraphEdge> children = entry->children();
Vector<HeapGraphEdge*> children = entry->children();
for (int i = 0; i < children.length(); ++i) {
HeapEntry* child = children[i].to();
HeapEntry* child = children[i]->to();
if (!child->user_reachable()) {
worklist.Add(child);
}
......@@ -3470,11 +3213,11 @@ void HeapSnapshotGenerator::FillPostorderIndexes(
snapshot_->root()->paint();
while (!nodes_to_visit.is_empty()) {
HeapEntry* entry = nodes_to_visit.last();
Vector<HeapGraphEdge> children = entry->children();
Vector<HeapGraphEdge*> children = entry->children();
bool has_new_edges = false;
for (int i = 0; i < children.length(); ++i) {
if (entry != root && !IsRetainingEdge(&children[i])) continue;
HeapEntry* child = children[i].to();
if (entry != root && !IsRetainingEdge(children[i])) continue;
HeapEntry* child = children[i]->to();
if (!child->painted()) {
nodes_to_visit.Add(child);
child->paint();
......@@ -3482,7 +3225,7 @@ void HeapSnapshotGenerator::FillPostorderIndexes(
}
}
if (!has_new_edges) {
entry->set_ordered_index(current_entry);
entry->set_postorder_index(current_entry);
(*entries)[current_entry++] = entry;
nodes_to_visit.RemoveLast();
}
......@@ -3510,8 +3253,7 @@ bool HeapSnapshotGenerator::BuildDominatorTree(
if (entries.length() == 0) return true;
HeapEntry* root = snapshot_->root();
const int entries_length = entries.length(), root_index = entries_length - 1;
static const int kNoDominator = -1;
for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator;
for (int i = 0; i < root_index; ++i) (*dominators)[i] = HeapEntry::kNoEntry;
(*dominators)[root_index] = root_index;
// The affected array is used to mark entries which dominators
......@@ -3519,28 +3261,28 @@ bool HeapSnapshotGenerator::BuildDominatorTree(
ScopedVector<bool> affected(entries_length);
for (int i = 0; i < affected.length(); ++i) affected[i] = false;
// Mark the root direct children as affected.
Vector<HeapGraphEdge> children = entries[root_index]->children();
Vector<HeapGraphEdge*> children = entries[root_index]->children();
for (int i = 0; i < children.length(); ++i) {
affected[children[i].to()->ordered_index()] = true;
affected[children[i]->to()->postorder_index()] = true;
}
bool changed = true;
while (changed) {
changed = false;
if (!ProgressReport(true)) return false;
if (!ProgressReport(false)) return false;
for (int i = root_index - 1; i >= 0; --i) {
if (!affected[i]) continue;
affected[i] = false;
// If dominator of the entry has already been set to root,
// then it can't propagate any further.
if ((*dominators)[i] == root_index) continue;
int new_idom_index = kNoDominator;
int new_idom_index = HeapEntry::kNoEntry;
Vector<HeapGraphEdge*> rets = entries[i]->retainers();
for (int j = 0; j < rets.length(); ++j) {
if (rets[j]->from() != root && !IsRetainingEdge(rets[j])) continue;
int ret_index = rets[j]->from()->ordered_index();
if (dominators->at(ret_index) != kNoDominator) {
new_idom_index = new_idom_index == kNoDominator
int ret_index = rets[j]->from()->postorder_index();
if (dominators->at(ret_index) != HeapEntry::kNoEntry) {
new_idom_index = new_idom_index == HeapEntry::kNoEntry
? ret_index
: Intersect(ret_index, new_idom_index, *dominators);
// If idom has already reached the root, it doesn't make sense
......@@ -3548,13 +3290,13 @@ bool HeapSnapshotGenerator::BuildDominatorTree(
if (new_idom_index == root_index) break;
}
}
if (new_idom_index != kNoDominator
if (new_idom_index != HeapEntry::kNoEntry
&& dominators->at(i) != new_idom_index) {
(*dominators)[i] = new_idom_index;
changed = true;
Vector<HeapGraphEdge> children = entries[i]->children();
Vector<HeapGraphEdge*> children = entries[i]->children();
for (int j = 0; j < children.length(); ++j) {
affected[children[j].to()->ordered_index()] = true;
affected[children[j]->to()->postorder_index()] = true;
}
}
}
......@@ -3566,12 +3308,12 @@ bool HeapSnapshotGenerator::BuildDominatorTree(
bool HeapSnapshotGenerator::SetEntriesDominators() {
MarkUserReachableObjects();
// This array is used for maintaining postorder of nodes.
ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length());
ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries().length());
FillPostorderIndexes(&ordered_entries);
ScopedVector<int> dominators(ordered_entries.length());
if (!BuildDominatorTree(ordered_entries, &dominators)) return false;
for (int i = 0; i < ordered_entries.length(); ++i) {
ASSERT(dominators[i] >= 0);
ASSERT(dominators[i] != HeapEntry::kNoEntry);
ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]);
}
return true;
......@@ -3582,17 +3324,18 @@ bool HeapSnapshotGenerator::CalculateRetainedSizes() {
// As for the dominators tree we only know parent nodes, not
// children, to sum up total sizes we "bubble" node's self size
// adding it to all of its parents.
List<HeapEntry*>& entries = *snapshot_->entries();
List<HeapEntry>& entries = snapshot_->entries();
for (int i = 0; i < entries.length(); ++i) {
HeapEntry* entry = entries[i];
HeapEntry* entry = &entries[i];
entry->set_retained_size(entry->self_size());
}
for (int i = 0; i < entries.length(); ++i) {
HeapEntry* entry = entries[i];
int entry_size = entry->self_size();
for (HeapEntry* dominator = entry->dominator();
dominator != entry;
entry = dominator, dominator = entry->dominator()) {
int entry_size = entries[i].self_size();
HeapEntry* current = &entries[i];
for (HeapEntry* dominator = current->dominator();
dominator != current;
current = dominator, dominator = current->dominator()) {
ASSERT(current->dominator() != NULL);
dominator->add_retained_size(entry_size);
}
}
......@@ -3696,19 +3439,23 @@ class OutputStreamWriter {
};
// type, name|index, to_node.
const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3;
// type, name, id, self_size, retained_size, dominator, children_index.
const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 7;
void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
ASSERT(writer_ == NULL);
writer_ = new OutputStreamWriter(stream);
HeapSnapshot* original_snapshot = NULL;
if (snapshot_->raw_entries_size() >=
if (snapshot_->RawSnapshotSize() >=
SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize) {
// The snapshot is too big. Serialize a fake snapshot.
original_snapshot = snapshot_;
snapshot_ = CreateFakeSnapshot();
}
// Since nodes graph is cyclic, we need the first pass to enumerate
// them. Strings can be serialized in one pass.
SerializeImpl();
delete writer_;
......@@ -3726,42 +3473,24 @@ HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() {
HeapSnapshot::kFull,
snapshot_->title(),
snapshot_->uid());
result->AllocateEntries(2, 1, 0);
HeapEntry* root = result->AddRootEntry(1);
result->AddRootEntry();
const char* text = snapshot_->collection()->names()->GetFormatted(
"The snapshot is too big. "
"Maximum snapshot size is %" V8_PTR_PREFIX "u MB. "
"Actual snapshot size is %" V8_PTR_PREFIX "u MB.",
SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize / MB,
(snapshot_->raw_entries_size() + MB - 1) / MB);
HeapEntry* message = result->AddEntry(
HeapEntry::kString, text, 0, 4, 0, 0);
root->SetUnidirElementReference(0, 1, message);
(snapshot_->RawSnapshotSize() + MB - 1) / MB);
HeapEntry* message = result->AddEntry(HeapEntry::kString, text, 0, 4);
result->root()->SetIndexedReference(HeapGraphEdge::kElement, 1, message);
result->FillChildrenAndRetainers();
result->SetDominatorsToSelf();
return result;
}
void HeapSnapshotJSONSerializer::CalculateNodeIndexes(
const List<HeapEntry*>& nodes) {
// type,name,id,self_size,retained_size,dominator,children_index.
const int node_fields_count = 7;
// Root must be the first.
ASSERT(nodes.first() == snapshot_->root());
// Rewrite node indexes, so they refer to actual array positions. Do this
// only once.
if (nodes[0]->entry_index() == -1) {
int index = 0;
for (int i = 0; i < nodes.length(); ++i, index += node_fields_count) {
nodes[i]->set_entry_index(index);
}
}
}
void HeapSnapshotJSONSerializer::SerializeImpl() {
List<HeapEntry*>& nodes = *(snapshot_->entries());
CalculateNodeIndexes(nodes);
List<HeapEntry>& nodes = snapshot_->entries();
ASSERT(0 == snapshot_->root()->index());
writer_->AddCharacter('{');
writer_->AddString("\"snapshot\":{");
SerializeSnapshot();
......@@ -3837,19 +3566,19 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
buffer[buffer_pos++] = ',';
buffer_pos = itoa(edge_name_or_index, buffer, buffer_pos);
buffer[buffer_pos++] = ',';
buffer_pos = itoa(edge->to()->entry_index(), buffer, buffer_pos);
buffer_pos = itoa(entry_index(edge->to()), buffer, buffer_pos);
buffer[buffer_pos++] = '\0';
writer_->AddString(buffer.start());
}
void HeapSnapshotJSONSerializer::SerializeEdges(const List<HeapEntry*>& nodes) {
void HeapSnapshotJSONSerializer::SerializeEdges(const List<HeapEntry>& nodes) {
bool first_edge = true;
for (int i = 0; i < nodes.length(); ++i) {
HeapEntry* entry = nodes[i];
Vector<HeapGraphEdge> children = entry->children();
HeapEntry* entry = &nodes[i];
Vector<HeapGraphEdge*> children = entry->children();
for (int j = 0; j < children.length(); ++j) {
SerializeEdge(&children[j], first_edge);
SerializeEdge(children[j], first_edge);
first_edge = false;
if (writer_->aborted()) return;
}
......@@ -3867,7 +3596,7 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry,
EmbeddedVector<char, kBufferSize> buffer;
int buffer_pos = 0;
buffer[buffer_pos++] = '\n';
if (entry->entry_index() != 0) {
if (entry_index(entry) != 0) {
buffer[buffer_pos++] = ',';
}
buffer_pos = itoa(entry->type(), buffer, buffer_pos);
......@@ -3880,7 +3609,7 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry,
buffer[buffer_pos++] = ',';
buffer_pos = itoa(entry->retained_size(), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
buffer_pos = itoa(entry->dominator()->entry_index(), buffer, buffer_pos);
buffer_pos = itoa(entry_index(entry->dominator()), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
buffer_pos = itoa(edges_index, buffer, buffer_pos);
buffer[buffer_pos++] = '\0';
......@@ -3888,13 +3617,12 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry,
}
void HeapSnapshotJSONSerializer::SerializeNodes(const List<HeapEntry*>& nodes) {
const int edge_fields_count = 3; // type,name|index,to_node.
void HeapSnapshotJSONSerializer::SerializeNodes(const List<HeapEntry>& nodes) {
int edges_index = 0;
for (int i = 0; i < nodes.length(); ++i) {
HeapEntry* entry = nodes[i];
HeapEntry* entry = &nodes[i];
SerializeNode(entry, edges_index);
edges_index += entry->children().length() * edge_fields_count;
edges_index += entry->children().length() * kEdgeFieldsCount;
if (writer_->aborted()) return;
}
}
......@@ -3958,9 +3686,9 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
#undef JSON_O
#undef JSON_A
writer_->AddString(",\"node_count\":");
writer_->AddNumber(snapshot_->entries()->length());
writer_->AddNumber(snapshot_->entries().length());
writer_->AddString(",\"edge_count\":");
writer_->AddNumber(snapshot_->number_of_edges());
writer_->AddNumber(snapshot_->edges().length());
}
......
......@@ -446,6 +446,7 @@ class ProfileGenerator {
class HeapEntry;
class HeapSnapshot;
class HeapGraphEdge BASE_EMBEDDED {
public:
......@@ -460,9 +461,9 @@ class HeapGraphEdge BASE_EMBEDDED {
};
HeapGraphEdge() { }
void Init(int child_index, Type type, const char* name, HeapEntry* to);
void Init(int child_index, Type type, int index, HeapEntry* to);
void Init(int child_index, int index, HeapEntry* to);
HeapGraphEdge(Type type, const char* name, int from, int to);
HeapGraphEdge(Type type, int index, int from, int to);
void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);
Type type() const { return static_cast<Type>(type_); }
int index() const {
......@@ -471,48 +472,34 @@ class HeapGraphEdge BASE_EMBEDDED {
}
const char* name() const {
ASSERT(type_ == kContextVariable
|| type_ == kProperty
|| type_ == kInternal
|| type_ == kShortcut);
|| type_ == kProperty
|| type_ == kInternal
|| type_ == kShortcut);
return name_;
}
HeapEntry* to() const { return to_; }
INLINE(HeapEntry* from() const);
HeapEntry* to() const { return to_entry_; }
private:
int child_index_ : 29;
INLINE(HeapSnapshot* snapshot() const);
unsigned type_ : 3;
int from_index_ : 29;
union {
// During entries population |to_index_| is used for storing the index,
// afterwards it is replaced with a pointer to the entry.
int to_index_;
HeapEntry* to_entry_;
};
union {
int index_;
const char* name_;
};
HeapEntry* to_;
DISALLOW_COPY_AND_ASSIGN(HeapGraphEdge);
};
class HeapSnapshot;
// HeapEntry instances represent an entity from the heap (or a special
// virtual node, e.g. root). To make heap snapshots more compact,
// HeapEntries has a special memory layout (no Vectors or Lists used):
//
// +-----------------+
// HeapEntry
// +-----------------+
// HeapGraphEdge |
// ... } children_count
// HeapGraphEdge |
// +-----------------+
// HeapGraphEdge* |
// ... } retainers_count
// HeapGraphEdge* |
// +-----------------+
//
// In a HeapSnapshot, all entries are hand-allocated in a continuous array
// of raw bytes.
//
// virtual node, e.g. root).
class HeapEntry BASE_EMBEDDED {
public:
enum Type {
......@@ -527,15 +514,14 @@ class HeapEntry BASE_EMBEDDED {
kNative = v8::HeapGraphNode::kNative,
kSynthetic = v8::HeapGraphNode::kSynthetic
};
static const int kNoEntry;
HeapEntry() { }
void Init(HeapSnapshot* snapshot,
HeapEntry(HeapSnapshot* snapshot,
Type type,
const char* name,
SnapshotObjectId id,
int self_size,
int children_count,
int retainers_count);
int self_size);
HeapSnapshot* snapshot() { return snapshot_; }
Type type() { return static_cast<Type>(type_); }
......@@ -545,20 +531,27 @@ class HeapEntry BASE_EMBEDDED {
int self_size() { return self_size_; }
int retained_size() { return retained_size_; }
void add_retained_size(int size) { retained_size_ += size; }
void set_retained_size(int value) { retained_size_ = value; }
int ordered_index() { return ordered_index_; }
void set_ordered_index(int value) { ordered_index_ = value; }
int entry_index() { return entry_index_; }
void set_entry_index(int value) { entry_index_ = value; }
Vector<HeapGraphEdge> children() {
return Vector<HeapGraphEdge>(children_arr(), children_count_); }
void set_retained_size(int size) { retained_size_ = size; }
INLINE(int index() const);
int postorder_index() { return postorder_index_; }
void set_postorder_index(int value) { postorder_index_ = value; }
int children_count() const { return children_count_; }
INLINE(int set_children_index(int index));
INLINE(int set_retainers_index(int index));
void add_child(HeapGraphEdge* edge) {
children_arr()[children_count_++] = edge;
}
void add_retainer(HeapGraphEdge* edge) {
retainers_arr()[retainers_count_++] = edge;
}
Vector<HeapGraphEdge*> children() {
return Vector<HeapGraphEdge*>(children_arr(), children_count_); }
Vector<HeapGraphEdge*> retainers() {
return Vector<HeapGraphEdge*>(retainers_arr(), retainers_count_); }
HeapEntry* dominator() { return dominator_; }
INLINE(HeapEntry* dominator() const);
void set_dominator(HeapEntry* entry) {
ASSERT(entry != NULL);
dominator_ = entry;
dominator_ = entry->index();
}
void clear_paint() { painted_ = false; }
bool painted() { return painted_; }
......@@ -566,57 +559,37 @@ class HeapEntry BASE_EMBEDDED {
bool user_reachable() { return user_reachable_; }
void set_user_reachable() { user_reachable_ = true; }
void SetIndexedReference(HeapGraphEdge::Type type,
int child_index,
int index,
HeapEntry* entry,
int retainer_index);
void SetNamedReference(HeapGraphEdge::Type type,
int child_index,
const char* name,
HeapEntry* entry,
int retainer_index);
void SetUnidirElementReference(int child_index, int index, HeapEntry* entry);
size_t EntrySize() {
return EntriesSize(1, children_count_, retainers_count_);
}
void SetIndexedReference(
HeapGraphEdge::Type type, int index, HeapEntry* entry);
void SetNamedReference(
HeapGraphEdge::Type type, const char* name, HeapEntry* entry);
void Print(
const char* prefix, const char* edge_name, int max_depth, int indent);
Handle<HeapObject> GetHeapObject();
static size_t EntriesSize(int entries_count,
int children_count,
int retainers_count);
private:
HeapGraphEdge* children_arr() {
return reinterpret_cast<HeapGraphEdge*>(this + 1);
}
HeapGraphEdge** retainers_arr() {
return reinterpret_cast<HeapGraphEdge**>(children_arr() + children_count_);
}
INLINE(HeapGraphEdge** children_arr());
INLINE(HeapGraphEdge** retainers_arr());
const char* TypeAsString();
unsigned painted_: 1;
unsigned user_reachable_: 1;
int dominator_: 30;
unsigned type_: 4;
int children_count_: 26;
int retainers_count_;
int retainers_count_: 28;
int retainers_index_;
int children_count_;
int children_index_;
int self_size_;
union {
int ordered_index_; // Used during dominator tree building.
int retained_size_; // At that moment, there is no retained size yet.
int postorder_index_; // Used during dominator tree building.
int retained_size_; // At that moment, there is no retained size yet.
};
int entry_index_;
SnapshotObjectId id_;
HeapEntry* dominator_;
HeapSnapshot* snapshot_;
const char* name_;
DISALLOW_COPY_AND_ASSIGN(HeapEntry);
};
......@@ -637,63 +610,59 @@ class HeapSnapshot {
Type type,
const char* title,
unsigned uid);
~HeapSnapshot();
void Delete();
HeapSnapshotsCollection* collection() { return collection_; }
Type type() { return type_; }
const char* title() { return title_; }
unsigned uid() { return uid_; }
HeapEntry* root() { return root_entry_; }
HeapEntry* gc_roots() { return gc_roots_entry_; }
HeapEntry* natives_root() { return natives_root_entry_; }
HeapEntry* gc_subroot(int index) { return gc_subroot_entries_[index]; }
List<HeapEntry*>* entries() { return &entries_; }
size_t raw_entries_size() { return raw_entries_size_; }
int number_of_edges() { return number_of_edges_; }
size_t RawSnapshotSize() const;
HeapEntry* root() { return &entries_[root_index_]; }
HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; }
HeapEntry* natives_root() { return &entries_[natives_root_index_]; }
HeapEntry* gc_subroot(int index) {
return &entries_[gc_subroot_indexes_[index]];
}
List<HeapEntry>& entries() { return entries_; }
List<HeapGraphEdge>& edges() { return edges_; }
List<HeapGraphEdge*>& children() { return children_; }
List<HeapGraphEdge*>& retainers() { return retainers_; }
void RememberLastJSObjectId();
SnapshotObjectId max_snapshot_js_object_id() const {
return max_snapshot_js_object_id_;
}
void AllocateEntries(
int entries_count, int children_count, int retainers_count);
HeapEntry* AddEntry(HeapEntry::Type type,
const char* name,
SnapshotObjectId id,
int size,
int children_count,
int retainers_count);
HeapEntry* AddRootEntry(int children_count);
HeapEntry* AddGcRootsEntry(int children_count, int retainers_count);
HeapEntry* AddGcSubrootEntry(int tag,
int children_count,
int retainers_count);
HeapEntry* AddNativesRootEntry(int children_count, int retainers_count);
int size);
HeapEntry* AddRootEntry();
HeapEntry* AddGcRootsEntry();
HeapEntry* AddGcSubrootEntry(int tag);
HeapEntry* AddNativesRootEntry();
void ClearPaint();
HeapEntry* GetEntryById(SnapshotObjectId id);
List<HeapEntry*>* GetSortedEntriesList();
void SetDominatorsToSelf();
void FillChildrenAndRetainers();
void Print(int max_depth);
void PrintEntriesSize();
private:
HeapEntry* GetNextEntryToInit();
HeapSnapshotsCollection* collection_;
Type type_;
const char* title_;
unsigned uid_;
HeapEntry* root_entry_;
HeapEntry* gc_roots_entry_;
HeapEntry* natives_root_entry_;
HeapEntry* gc_subroot_entries_[VisitorSynchronization::kNumberOfSyncTags];
char* raw_entries_;
List<HeapEntry*> entries_;
int root_index_;
int gc_roots_index_;
int natives_root_index_;
int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags];
List<HeapEntry> entries_;
List<HeapGraphEdge> edges_;
List<HeapGraphEdge*> children_;
List<HeapGraphEdge*> retainers_;
List<HeapEntry*> sorted_entries_;
size_t raw_entries_size_;
int number_of_edges_;
SnapshotObjectId max_snapshot_js_object_id_;
friend class HeapSnapshotTester;
......@@ -828,8 +797,7 @@ typedef void* HeapThing;
class HeapEntriesAllocator {
public:
virtual ~HeapEntriesAllocator() { }
virtual HeapEntry* AllocateEntry(
HeapThing ptr, int children_count, int retainers_count) = 0;
virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0;
};
......@@ -838,37 +806,11 @@ class HeapEntriesAllocator {
class HeapEntriesMap {
public:
HeapEntriesMap();
~HeapEntriesMap();
void AllocateEntries(HeapThing root_object);
HeapEntry* Map(HeapThing thing);
void Pair(HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry);
void CountReference(HeapThing from, HeapThing to,
int* prev_children_count = NULL,
int* prev_retainers_count = NULL);
int entries_count() { return entries_count_; }
int total_children_count() { return total_children_count_; }
int total_retainers_count() { return total_retainers_count_; }
static HeapEntry* const kHeapEntryPlaceholder;
int Map(HeapThing thing);
void Pair(HeapThing thing, int entry);
private:
struct EntryInfo {
EntryInfo(HeapEntry* entry, HeapEntriesAllocator* allocator)
: entry(entry),
allocator(allocator),
children_count(0),
retainers_count(0) {
}
HeapEntry* entry;
HeapEntriesAllocator* allocator;
int children_count;
int retainers_count;
};
static inline void AllocateHeapEntryForMapEntry(HashMap::Entry* map_entry);
static uint32_t Hash(HeapThing thing) {
return ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)),
......@@ -879,9 +821,6 @@ class HeapEntriesMap {
}
HashMap entries_;
int entries_count_;
int total_children_count_;
int total_retainers_count_;
friend class HeapObjectsSet;
......@@ -916,26 +855,18 @@ class SnapshotFillerInterface {
virtual HeapEntry* FindOrAddEntry(HeapThing ptr,
HeapEntriesAllocator* allocator) = 0;
virtual void SetIndexedReference(HeapGraphEdge::Type type,
HeapThing parent_ptr,
HeapEntry* parent_entry,
int parent_entry,
int index,
HeapThing child_ptr,
HeapEntry* child_entry) = 0;
virtual void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
HeapThing parent_ptr,
HeapEntry* parent_entry,
HeapThing child_ptr,
int parent_entry,
HeapEntry* child_entry) = 0;
virtual void SetNamedReference(HeapGraphEdge::Type type,
HeapThing parent_ptr,
HeapEntry* parent_entry,
int parent_entry,
const char* reference_name,
HeapThing child_ptr,
HeapEntry* child_entry) = 0;
virtual void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
HeapThing parent_ptr,
HeapEntry* parent_entry,
HeapThing child_ptr,
int parent_entry,
HeapEntry* child_entry) = 0;
};
......@@ -954,8 +885,7 @@ class V8HeapExplorer : public HeapEntriesAllocator {
V8HeapExplorer(HeapSnapshot* snapshot,
SnapshottingProgressReportingInterface* progress);
virtual ~V8HeapExplorer();
virtual HeapEntry* AllocateEntry(
HeapThing ptr, int children_count, int retainers_count);
virtual HeapEntry* AllocateEntry(HeapThing ptr);
void AddRootEntries(SnapshotFillerInterface* filler);
int EstimateObjectsCount(HeapIterator* iterator);
bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
......@@ -967,75 +897,72 @@ class V8HeapExplorer : public HeapEntriesAllocator {
static HeapObject* const kInternalRootObject;
private:
HeapEntry* AddEntry(
HeapObject* object, int children_count, int retainers_count);
HeapEntry* AddEntry(HeapObject* object);
HeapEntry* AddEntry(HeapObject* object,
HeapEntry::Type type,
const char* name,
int children_count,
int retainers_count);
const char* name);
const char* GetSystemEntryName(HeapObject* object);
void ExtractReferences(HeapObject* obj);
void ExtractJSGlobalProxyReferences(JSGlobalProxy* proxy);
void ExtractJSObjectReferences(HeapEntry* entry, JSObject* js_obj);
void ExtractStringReferences(HeapEntry* entry, String* obj);
void ExtractContextReferences(HeapEntry* entry, Context* context);
void ExtractMapReferences(HeapEntry* entry, Map* map);
void ExtractSharedFunctionInfoReferences(HeapEntry* entry,
void ExtractJSObjectReferences(int entry, JSObject* js_obj);
void ExtractStringReferences(int entry, String* obj);
void ExtractContextReferences(int entry, Context* context);
void ExtractMapReferences(int entry, Map* map);
void ExtractSharedFunctionInfoReferences(int entry,
SharedFunctionInfo* shared);
void ExtractScriptReferences(HeapEntry* entry, Script* script);
void ExtractCodeCacheReferences(HeapEntry* entry, CodeCache* code_cache);
void ExtractCodeReferences(HeapEntry* entry, Code* code);
void ExtractJSGlobalPropertyCellReferences(HeapEntry* entry,
void ExtractScriptReferences(int entry, Script* script);
void ExtractCodeCacheReferences(int entry, CodeCache* code_cache);
void ExtractCodeReferences(int entry, Code* code);
void ExtractJSGlobalPropertyCellReferences(int entry,
JSGlobalPropertyCell* cell);
void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractClosureReferences(JSObject* js_obj, int entry);
void ExtractPropertyReferences(JSObject* js_obj, int entry);
void ExtractElementReferences(JSObject* js_obj, int entry);
void ExtractInternalReferences(JSObject* js_obj, int entry);
bool IsEssentialObject(Object* object);
void SetClosureReference(HeapObject* parent_obj,
HeapEntry* parent,
int parent,
String* reference_name,
Object* child);
void SetNativeBindReference(HeapObject* parent_obj,
HeapEntry* parent,
int parent,
const char* reference_name,
Object* child);
void SetElementReference(HeapObject* parent_obj,
HeapEntry* parent,
int parent,
int index,
Object* child);
void SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent,
int parent,
const char* reference_name,
Object* child,
int field_offset = -1);
void SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent,
int parent,
int index,
Object* child,
int field_offset = -1);
void SetHiddenReference(HeapObject* parent_obj,
HeapEntry* parent,
int parent,
int index,
Object* child);
void SetWeakReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int parent,
int index,
Object* child_obj,
int field_offset);
void SetPropertyReference(HeapObject* parent_obj,
HeapEntry* parent,
int parent,
String* reference_name,
Object* child,
const char* name_format_string = NULL,
int field_offset = -1);
void SetPropertyShortcutReference(HeapObject* parent_obj,
HeapEntry* parent,
int parent,
String* reference_name,
Object* child);
void SetUserGlobalReference(Object* window);
void SetUserGlobalReference(Object* user_global);
void SetRootGcRootsReference();
void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
void SetGcSubrootReference(
......@@ -1139,10 +1066,9 @@ class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
bool BuildDominatorTree(const Vector<HeapEntry*>& entries,
Vector<int>* dominators);
bool CalculateRetainedSizes();
bool CountEntriesAndReferences();
bool FillReferences();
void FillPostorderIndexes(Vector<HeapEntry*>* entries);
bool IsUserGlobalReference(const HeapGraphEdge& edge);
bool IsUserGlobalReference(const HeapGraphEdge* edge);
void MarkUserReachableObjects();
void ProgressStep();
bool ProgressReport(bool force = false);
......@@ -1186,20 +1112,21 @@ class HeapSnapshotJSONSerializer {
v8::internal::kZeroHashSeed);
}
void CalculateNodeIndexes(const List<HeapEntry*>& nodes);
HeapSnapshot* CreateFakeSnapshot();
int GetStringId(const char* s);
int entry_index(HeapEntry* e) { return e->index() * kNodeFieldsCount; }
void SerializeEdge(HeapGraphEdge* edge, bool first_edge);
void SerializeEdges(const List<HeapEntry*>& nodes);
void SerializeEdges(const List<HeapEntry>& nodes);
void SerializeImpl();
void SerializeNode(HeapEntry* entry, int edges_index);
void SerializeNodes(const List<HeapEntry*>& nodes);
void SerializeNodes(const List<HeapEntry>& nodes);
void SerializeSnapshot();
void SerializeString(const unsigned char* s);
void SerializeStrings();
void SortHashMap(HashMap* map, List<HashMap::Entry*>* sorted_entries);
static const int kMaxSerializableSnapshotRawSize;
static const int kEdgeFieldsCount;
static const int kNodeFieldsCount;
HeapSnapshot* snapshot_;
HashMap strings_;
......
......@@ -34,10 +34,10 @@ class NamedEntriesDetector {
CheckEntry(root);
while (!list.is_empty()) {
i::HeapEntry* entry = list.RemoveLast();
i::Vector<i::HeapGraphEdge> children = entry->children();
i::Vector<i::HeapGraphEdge*> children = entry->children();
for (int i = 0; i < children.length(); ++i) {
if (children[i].type() == i::HeapGraphEdge::kShortcut) continue;
i::HeapEntry* child = children[i].to();
if (children[i]->type() == i::HeapGraphEdge::kShortcut) continue;
i::HeapEntry* child = children[i]->to();
if (!child->painted()) {
list.Add(child);
child->paint();
......
......@@ -130,6 +130,18 @@ TEST(RemoveLast) {
}
TEST(Allocate) {
List<int> list(4);
list.Add(1);
CHECK_EQ(1, list.length());
list.Allocate(100);
CHECK_EQ(100, list.length());
CHECK_LE(100, list.capacity());
list[99] = 123;
CHECK_EQ(123, list[99]);
}
TEST(Clear) {
List<int> list(4);
CHECK_EQ(0, list.length());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment