Split nodes and edges into separate arrays in heap profiler.
authoralexeif@chromium.org <alexeif@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 9 May 2012 14:34:13 +0000 (14:34 +0000)
committeralexeif@chromium.org <alexeif@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 9 May 2012 14:34:13 +0000 (14:34 +0000)
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

src/api.cc
src/list-inl.h
src/list.h
src/profile-generator-inl.h
src/profile-generator.cc
src/profile-generator.h
test/cctest/test-heap-profiler.cc
test/cctest/test-list.cc

index 0bc93c2..52a84ed 100644 (file)
@@ -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));
 }
 
 
index 35ee3f5..6cf3bad 100644 (file)
@@ -137,6 +137,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_);
   Initialize(0);
index a210dfb..7350c0d 100644 (file)
@@ -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());
index 284e2df..9afc52f 100644 (file)
@@ -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_];
 }
 
 
index 821b1d0..214bfa4 100644 (file)
@@ -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());
 }
 
 
index e04ddbf..18c157c 100644 (file)
@@ -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_;
index 3ac1741..cbe8d44 100644 (file)
@@ -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();
index 7520b05..4c78f02 100644 (file)
@@ -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());