Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / v8 / src / heap-snapshot-generator.cc
index ccfbfb8..4a4c914 100644 (file)
@@ -1,39 +1,17 @@
 // Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "v8.h"
-
-#include "heap-snapshot-generator-inl.h"
-
-#include "allocation-tracker.h"
-#include "code-stubs.h"
-#include "heap-profiler.h"
-#include "debug.h"
-#include "types.h"
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/heap-snapshot-generator-inl.h"
+
+#include "src/allocation-tracker.h"
+#include "src/code-stubs.h"
+#include "src/conversions.h"
+#include "src/debug.h"
+#include "src/heap-profiler.h"
+#include "src/types.h"
 
 namespace v8 {
 namespace internal {
@@ -44,7 +22,7 @@ HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to)
       from_index_(from),
       to_index_(to),
       name_(name) {
-  ASSERT(type == kContextVariable
+  DCHECK(type == kContextVariable
       || type == kProperty
       || type == kInternal
       || type == kShortcut
@@ -57,7 +35,7 @@ HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to)
       from_index_(from),
       to_index_(to),
       index_(index) {
-  ASSERT(type == kElement || type == kHidden);
+  DCHECK(type == kElement || type == kHidden);
 }
 
 
@@ -72,14 +50,16 @@ HeapEntry::HeapEntry(HeapSnapshot* snapshot,
                      Type type,
                      const char* name,
                      SnapshotObjectId id,
-                     int self_size)
+                     size_t self_size,
+                     unsigned trace_node_id)
     : type_(type),
       children_count_(0),
       children_index_(-1),
       self_size_(self_size),
-      id_(id),
       snapshot_(snapshot),
-      name_(name) { }
+      name_(name),
+      id_(id),
+      trace_node_id_(trace_node_id) { }
 
 
 void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
@@ -102,22 +82,22 @@ void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
 
 void HeapEntry::Print(
     const char* prefix, const char* edge_name, int max_depth, int indent) {
-  STATIC_CHECK(sizeof(unsigned) == sizeof(id()));
-  OS::Print("%6d @%6u %*c %s%s: ",
-            self_size(), id(), indent, ' ', prefix, edge_name);
+  STATIC_ASSERT(sizeof(unsigned) == sizeof(id()));
+  base::OS::Print("%6" V8PRIuPTR " @%6u %*c %s%s: ", self_size(), id(), indent,
+                  ' ', prefix, edge_name);
   if (type() != kString) {
-    OS::Print("%s %.40s\n", TypeAsString(), name_);
+    base::OS::Print("%s %.40s\n", TypeAsString(), name_);
   } else {
-    OS::Print("\"");
+    base::OS::Print("\"");
     const char* c = name_;
     while (*c && (c - name_) <= 40) {
       if (*c != '\n')
-        OS::Print("%c", *c);
+        base::OS::Print("%c", *c);
       else
-        OS::Print("\\n");
+        base::OS::Print("\\n");
       ++c;
     }
-    OS::Print("\"\n");
+    base::OS::Print("\"\n");
   }
   if (--max_depth == 0) return;
   Vector<HeapGraphEdge*> ch = children();
@@ -132,7 +112,7 @@ void HeapEntry::Print(
         edge_name = edge.name();
         break;
       case HeapGraphEdge::kElement:
-        OS::SNPrintF(index, "%d", edge.index());
+        SNPrintF(index, "%d", edge.index());
         break;
       case HeapGraphEdge::kInternal:
         edge_prefix = "$";
@@ -143,7 +123,7 @@ void HeapEntry::Print(
         break;
       case HeapGraphEdge::kHidden:
         edge_prefix = "$";
-        OS::SNPrintF(index, "%d", edge.index());
+        SNPrintF(index, "%d", edge.index());
         break;
       case HeapGraphEdge::kShortcut:
         edge_prefix = "^";
@@ -154,7 +134,7 @@ void HeapEntry::Print(
         edge_name = edge.name();
         break;
       default:
-        OS::SNPrintF(index, "!!! unknown edge type: %d ", edge.type());
+        SNPrintF(index, "!!! unknown edge type: %d ", edge.type());
     }
     edge.to()->Print(edge_prefix, edge_name, max_depth, indent + 2);
   }
@@ -175,6 +155,7 @@ const char* HeapEntry::TypeAsString() {
     case kSynthetic: return "/synthetic/";
     case kConsString: return "/concatenated string/";
     case kSlicedString: return "/sliced string/";
+    case kSymbol: return "/symbol/";
     default: return "???";
   }
 }
@@ -188,12 +169,12 @@ template <size_t ptr_size> struct SnapshotSizeConstants;
 
 template <> struct SnapshotSizeConstants<4> {
   static const int kExpectedHeapGraphEdgeSize = 12;
-  static const int kExpectedHeapEntrySize = 24;
+  static const int kExpectedHeapEntrySize = 28;
 };
 
 template <> struct SnapshotSizeConstants<8> {
   static const int kExpectedHeapGraphEdgeSize = 24;
-  static const int kExpectedHeapEntrySize = 32;
+  static const int kExpectedHeapEntrySize = 40;
 };
 
 }  // namespace
@@ -207,12 +188,11 @@ HeapSnapshot::HeapSnapshot(HeapProfiler* profiler,
       uid_(uid),
       root_index_(HeapEntry::kNoEntry),
       gc_roots_index_(HeapEntry::kNoEntry),
-      natives_root_index_(HeapEntry::kNoEntry),
       max_snapshot_js_object_id_(0) {
-  STATIC_CHECK(
+  STATIC_ASSERT(
       sizeof(HeapGraphEdge) ==
       SnapshotSizeConstants<kPointerSize>::kExpectedHeapGraphEdgeSize);
-  STATIC_CHECK(
+  STATIC_ASSERT(
       sizeof(HeapEntry) ==
       SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize);
   USE(SnapshotSizeConstants<4>::kExpectedHeapGraphEdgeSize);
@@ -236,38 +216,49 @@ void HeapSnapshot::RememberLastJSObjectId() {
 }
 
 
+void HeapSnapshot::AddSyntheticRootEntries() {
+  AddRootEntry();
+  AddGcRootsEntry();
+  SnapshotObjectId id = HeapObjectsMap::kGcRootsFirstSubrootId;
+  for (int tag = 0; tag < VisitorSynchronization::kNumberOfSyncTags; tag++) {
+    AddGcSubrootEntry(tag, id);
+    id += HeapObjectsMap::kObjectIdStep;
+  }
+  DCHECK(HeapObjectsMap::kFirstAvailableObjectId == id);
+}
+
+
 HeapEntry* HeapSnapshot::AddRootEntry() {
-  ASSERT(root_index_ == HeapEntry::kNoEntry);
-  ASSERT(entries_.is_empty());  // Root entry must be the first one.
+  DCHECK(root_index_ == HeapEntry::kNoEntry);
+  DCHECK(entries_.is_empty());  // Root entry must be the first one.
   HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
                               "",
                               HeapObjectsMap::kInternalRootObjectId,
+                              0,
                               0);
   root_index_ = entry->index();
-  ASSERT(root_index_ == 0);
+  DCHECK(root_index_ == 0);
   return entry;
 }
 
 
 HeapEntry* HeapSnapshot::AddGcRootsEntry() {
-  ASSERT(gc_roots_index_ == HeapEntry::kNoEntry);
+  DCHECK(gc_roots_index_ == HeapEntry::kNoEntry);
   HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
                               "(GC roots)",
                               HeapObjectsMap::kGcRootsObjectId,
+                              0,
                               0);
   gc_roots_index_ = entry->index();
   return entry;
 }
 
 
-HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag) {
-  ASSERT(gc_subroot_indexes_[tag] == HeapEntry::kNoEntry);
-  ASSERT(0 <= tag && tag < VisitorSynchronization::kNumberOfSyncTags);
-  HeapEntry* entry = AddEntry(
-      HeapEntry::kSynthetic,
-      VisitorSynchronization::kTagNames[tag],
-      HeapObjectsMap::GetNthGcSubrootId(tag),
-      0);
+HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag, SnapshotObjectId id) {
+  DCHECK(gc_subroot_indexes_[tag] == HeapEntry::kNoEntry);
+  DCHECK(0 <= tag && tag < VisitorSynchronization::kNumberOfSyncTags);
+  HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
+                              VisitorSynchronization::kTagNames[tag], id, 0, 0);
   gc_subroot_indexes_[tag] = entry->index();
   return entry;
 }
@@ -276,22 +267,23 @@ HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag) {
 HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
                                   const char* name,
                                   SnapshotObjectId id,
-                                  int size) {
-  HeapEntry entry(this, type, name, id, size);
+                                  size_t size,
+                                  unsigned trace_node_id) {
+  HeapEntry entry(this, type, name, id, size, trace_node_id);
   entries_.Add(entry);
   return &entries_.last();
 }
 
 
 void HeapSnapshot::FillChildren() {
-  ASSERT(children().is_empty());
+  DCHECK(children().is_empty());
   children().Allocate(edges().length());
   int children_index = 0;
   for (int i = 0; i < entries().length(); ++i) {
     HeapEntry* entry = &entries()[i];
     children_index = entry->set_children_index(children_index);
   }
-  ASSERT(edges().length() == children_index);
+  DCHECK(edges().length() == children_index);
   for (int i = 0; i < edges().length(); ++i) {
     HeapGraphEdge* edge = &edges()[i];
     edge->ReplaceToIndexWithEntry(this);
@@ -389,10 +381,10 @@ HeapObjectsMap::HeapObjectsMap(Heap* heap)
 }
 
 
-void HeapObjectsMap::MoveObject(Address from, Address to, int object_size) {
-  ASSERT(to != NULL);
-  ASSERT(from != NULL);
-  if (from == to) return;
+bool HeapObjectsMap::MoveObject(Address from, Address to, int object_size) {
+  DCHECK(to != NULL);
+  DCHECK(from != NULL);
+  if (from == to) return false;
   void* from_value = entries_map_.Remove(from, ComputePointerHash(from));
   if (from_value == NULL) {
     // It may occur that some untracked object moves to an address X and there
@@ -433,6 +425,7 @@ void HeapObjectsMap::MoveObject(Address from, Address to, int object_size) {
     entries_.at(from_entry_info_index).size = object_size;
     to_entry->value = from_value;
   }
+  return from_value != NULL;
 }
 
 
@@ -447,7 +440,7 @@ SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) {
   if (entry == NULL) return 0;
   int entry_index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
   EntryInfo& entry_info = entries_.at(entry_index);
-  ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
+  DCHECK(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
   return entry_info.id;
 }
 
@@ -455,7 +448,7 @@ SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) {
 SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr,
                                                 unsigned int size,
                                                 bool accessed) {
-  ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
+  DCHECK(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
   HashMap::Entry* entry = entries_map_.Lookup(addr, ComputePointerHash(addr),
                                               true);
   if (entry->value != NULL) {
@@ -476,7 +469,7 @@ SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr,
   SnapshotObjectId id = next_id_;
   next_id_ += kObjectIdStep;
   entries_.Add(EntryInfo(id, addr, size, accessed));
-  ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
+  DCHECK(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
   return id;
 }
 
@@ -629,7 +622,7 @@ SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) {
   time_intervals_.Add(TimeInterval(next_id_));
   int prefered_chunk_size = stream->GetChunkSize();
   List<v8::HeapStatsUpdate> stats_buffer;
-  ASSERT(!entries_.is_empty());
+  DCHECK(!entries_.is_empty());
   EntryInfo* entry_info = &entries_.first();
   EntryInfo* end_entry_info = &entries_.last() + 1;
   for (int time_interval_index = 0;
@@ -659,7 +652,7 @@ SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) {
       }
     }
   }
-  ASSERT(entry_info == end_entry_info);
+  DCHECK(entry_info == end_entry_info);
   if (!stats_buffer.is_empty()) {
     OutputStream::WriteResult result = stream->WriteHeapStatsChunk(
         &stats_buffer.first(), stats_buffer.length());
@@ -671,7 +664,7 @@ SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) {
 
 
 void HeapObjectsMap::RemoveDeadEntries() {
-  ASSERT(entries_.length() > 0 &&
+  DCHECK(entries_.length() > 0 &&
          entries_.at(0).id == 0 &&
          entries_.at(0).addr == NULL);
   int first_free_entry = 1;
@@ -684,7 +677,7 @@ void HeapObjectsMap::RemoveDeadEntries() {
       entries_.at(first_free_entry).accessed = false;
       HashMap::Entry* entry = entries_map_.Lookup(
           entry_info.addr, ComputePointerHash(entry_info.addr), false);
-      ASSERT(entry);
+      DCHECK(entry);
       entry->value = reinterpret_cast<void*>(first_free_entry);
       ++first_free_entry;
     } else {
@@ -695,7 +688,7 @@ void HeapObjectsMap::RemoveDeadEntries() {
     }
   }
   entries_.Rewind(first_free_entry);
-  ASSERT(static_cast<uint32_t>(entries_.length()) - 1 ==
+  DCHECK(static_cast<uint32_t>(entries_.length()) - 1 ==
          entries_map_.occupancy());
 }
 
@@ -724,7 +717,7 @@ size_t HeapObjectsMap::GetUsedMemorySize() const {
 
 
 HeapEntriesMap::HeapEntriesMap()
-    : entries_(HeapThingsMatch) {
+    : entries_(HashMap::PointersMatch) {
 }
 
 
@@ -737,13 +730,13 @@ int HeapEntriesMap::Map(HeapThing thing) {
 
 void HeapEntriesMap::Pair(HeapThing thing, int entry) {
   HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), true);
-  ASSERT(cache_entry->value == NULL);
+  DCHECK(cache_entry->value == NULL);
   cache_entry->value = reinterpret_cast<void*>(static_cast<intptr_t>(entry));
 }
 
 
 HeapObjectsSet::HeapObjectsSet()
-    : entries_(HeapEntriesMap::HeapThingsMatch) {
+    : entries_(HashMap::PointersMatch) {
 }
 
 
@@ -785,20 +778,6 @@ void HeapObjectsSet::SetTag(Object* obj, const char* tag) {
 }
 
 
-HeapObject* const V8HeapExplorer::kInternalRootObject =
-    reinterpret_cast<HeapObject*>(
-        static_cast<intptr_t>(HeapObjectsMap::kInternalRootObjectId));
-HeapObject* const V8HeapExplorer::kGcRootsObject =
-    reinterpret_cast<HeapObject*>(
-        static_cast<intptr_t>(HeapObjectsMap::kGcRootsObjectId));
-HeapObject* const V8HeapExplorer::kFirstGcSubrootObject =
-    reinterpret_cast<HeapObject*>(
-        static_cast<intptr_t>(HeapObjectsMap::kGcRootsFirstSubrootId));
-HeapObject* const V8HeapExplorer::kLastGcSubrootObject =
-    reinterpret_cast<HeapObject*>(
-        static_cast<intptr_t>(HeapObjectsMap::kFirstAvailableObjectId));
-
-
 V8HeapExplorer::V8HeapExplorer(
     HeapSnapshot* snapshot,
     SnapshottingProgressReportingInterface* progress,
@@ -823,16 +802,7 @@ HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) {
 
 
 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) {
-  if (object == kInternalRootObject) {
-    snapshot_->AddRootEntry();
-    return snapshot_->root();
-  } else if (object == kGcRootsObject) {
-    HeapEntry* entry = snapshot_->AddGcRootsEntry();
-    return entry;
-  } else if (object >= kFirstGcSubrootObject && object < kLastGcSubrootObject) {
-    HeapEntry* entry = snapshot_->AddGcSubrootEntry(GetGcSubrootOrder(object));
-    return entry;
-  } else if (object->IsJSFunction()) {
+  if (object->IsJSFunction()) {
     JSFunction* func = JSFunction::cast(object);
     SharedFunctionInfo* shared = func->shared();
     const char* name = shared->bound() ? "native_bind" :
@@ -866,6 +836,8 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) {
     return AddEntry(object,
                     HeapEntry::kString,
                     names_->GetName(String::cast(object)));
+  } else if (object->IsSymbol()) {
+    return AddEntry(object, HeapEntry::kSymbol, "symbol");
   } else if (object->IsCode()) {
     return AddEntry(object, HeapEntry::kCode, "");
   } else if (object->IsSharedFunctionInfo()) {
@@ -899,48 +871,84 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) {
 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
                                     HeapEntry::Type type,
                                     const char* name) {
-  int object_size = object->Size();
-  SnapshotObjectId object_id =
-      heap_object_map_->FindOrAddEntry(object->address(), object_size);
-  return snapshot_->AddEntry(type, name, object_id, object_size);
+  return AddEntry(object->address(), type, name, object->Size());
 }
 
 
-class GcSubrootsEnumerator : public ObjectVisitor {
+HeapEntry* V8HeapExplorer::AddEntry(Address address,
+                                    HeapEntry::Type type,
+                                    const char* name,
+                                    size_t size) {
+  SnapshotObjectId object_id = heap_object_map_->FindOrAddEntry(
+      address, static_cast<unsigned int>(size));
+  unsigned trace_node_id = 0;
+  if (AllocationTracker* allocation_tracker =
+      snapshot_->profiler()->allocation_tracker()) {
+    trace_node_id =
+        allocation_tracker->address_to_trace()->GetTraceNodeId(address);
+  }
+  return snapshot_->AddEntry(type, name, object_id, size, trace_node_id);
+}
+
+
+class SnapshotFiller {
  public:
-  GcSubrootsEnumerator(
-      SnapshotFillerInterface* filler, V8HeapExplorer* explorer)
-      : filler_(filler),
-        explorer_(explorer),
-        previous_object_count_(0),
-        object_count_(0) {
+  explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries)
+      : snapshot_(snapshot),
+        names_(snapshot->profiler()->names()),
+        entries_(entries) { }
+  HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
+    HeapEntry* entry = allocator->AllocateEntry(ptr);
+    entries_->Pair(ptr, entry->index());
+    return entry;
   }
-  void VisitPointers(Object** start, Object** end) {
-    object_count_ += end - start;
+  HeapEntry* FindEntry(HeapThing ptr) {
+    int index = entries_->Map(ptr);
+    return index != HeapEntry::kNoEntry ? &snapshot_->entries()[index] : NULL;
   }
-  void Synchronize(VisitorSynchronization::SyncTag tag) {
-    // Skip empty subroots.
-    if (previous_object_count_ != object_count_) {
-      previous_object_count_ = object_count_;
-      filler_->AddEntry(V8HeapExplorer::GetNthGcSubrootObject(tag), explorer_);
-    }
+  HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
+    HeapEntry* entry = FindEntry(ptr);
+    return entry != NULL ? entry : AddEntry(ptr, allocator);
+  }
+  void SetIndexedReference(HeapGraphEdge::Type type,
+                           int parent,
+                           int index,
+                           HeapEntry* child_entry) {
+    HeapEntry* parent_entry = &snapshot_->entries()[parent];
+    parent_entry->SetIndexedReference(type, index, child_entry);
+  }
+  void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
+                                    int parent,
+                                    HeapEntry* child_entry) {
+    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,
+                         int parent,
+                         const char* reference_name,
+                         HeapEntry* child_entry) {
+    HeapEntry* parent_entry = &snapshot_->entries()[parent];
+    parent_entry->SetNamedReference(type, reference_name, child_entry);
   }
+  void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
+                                  int parent,
+                                  HeapEntry* child_entry) {
+    HeapEntry* parent_entry = &snapshot_->entries()[parent];
+    int index = parent_entry->children_count() + 1;
+    parent_entry->SetNamedReference(
+        type,
+        names_->GetName(index),
+        child_entry);
+  }
+
  private:
-  SnapshotFillerInterface* filler_;
-  V8HeapExplorer* explorer_;
-  intptr_t previous_object_count_;
-  intptr_t object_count_;
+  HeapSnapshot* snapshot_;
+  StringsStorage* names_;
+  HeapEntriesMap* entries_;
 };
 
 
-void V8HeapExplorer::AddRootEntries(SnapshotFillerInterface* filler) {
-  filler->AddEntry(kInternalRootObject, this);
-  filler->AddEntry(kGcRootsObject, this);
-  GcSubrootsEnumerator enumerator(filler, this);
-  heap_->IterateRoots(&enumerator, VISIT_ALL);
-}
-
-
 const char* V8HeapExplorer::GetSystemEntryName(HeapObject* object) {
   switch (object->map()->instance_type()) {
     case MAP_TYPE:
@@ -1000,21 +1008,30 @@ class IndexedReferencesExtractor : public ObjectVisitor {
   static void MarkVisitedField(HeapObject* obj, int offset) {
     if (offset < 0) return;
     Address field = obj->address() + offset;
-    ASSERT(!Memory::Object_at(field)->IsFailure());
-    ASSERT(Memory::Object_at(field)->IsHeapObject());
-    *field |= kFailureTag;
+    DCHECK(Memory::Object_at(field)->IsHeapObject());
+    intptr_t p = reinterpret_cast<intptr_t>(Memory::Object_at(field));
+    DCHECK(!IsMarked(p));
+    intptr_t p_tagged = p | kTag;
+    Memory::Object_at(field) = reinterpret_cast<Object*>(p_tagged);
   }
 
  private:
   bool CheckVisitedAndUnmark(Object** field) {
-    if ((*field)->IsFailure()) {
-      intptr_t untagged = reinterpret_cast<intptr_t>(*field) & ~kFailureTagMask;
-      *field = reinterpret_cast<Object*>(untagged | kHeapObjectTag);
-      ASSERT((*field)->IsHeapObject());
+    intptr_t p = reinterpret_cast<intptr_t>(*field);
+    if (IsMarked(p)) {
+      intptr_t p_untagged = (p & ~kTaggingMask) | kHeapObjectTag;
+      *field = reinterpret_cast<Object*>(p_untagged);
+      DCHECK((*field)->IsHeapObject());
       return true;
     }
     return false;
   }
+
+  static const intptr_t kTaggingMask = 3;
+  static const intptr_t kTag = 3;
+
+  static bool IsMarked(intptr_t p) { return (p & kTaggingMask) == kTag; }
+
   V8HeapExplorer* generator_;
   HeapObject* parent_obj_;
   int parent_;
@@ -1022,25 +1039,36 @@ class IndexedReferencesExtractor : public ObjectVisitor {
 };
 
 
-void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
-  HeapEntry* heap_entry = GetEntry(obj);
-  if (heap_entry == NULL) return;  // No interest in this object.
-  int entry = heap_entry->index();
+bool V8HeapExplorer::ExtractReferencesPass1(int entry, HeapObject* obj) {
+  if (obj->IsFixedArray()) return false;  // FixedArrays are processed on pass 2
 
   if (obj->IsJSGlobalProxy()) {
     ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
+  } else if (obj->IsJSArrayBuffer()) {
+    ExtractJSArrayBufferReferences(entry, JSArrayBuffer::cast(obj));
   } else if (obj->IsJSObject()) {
+    if (obj->IsJSWeakSet()) {
+      ExtractJSWeakCollectionReferences(entry, JSWeakSet::cast(obj));
+    } else if (obj->IsJSWeakMap()) {
+      ExtractJSWeakCollectionReferences(entry, JSWeakMap::cast(obj));
+    } else if (obj->IsJSSet()) {
+      ExtractJSCollectionReferences(entry, JSSet::cast(obj));
+    } else if (obj->IsJSMap()) {
+      ExtractJSCollectionReferences(entry, JSMap::cast(obj));
+    }
     ExtractJSObjectReferences(entry, JSObject::cast(obj));
   } else if (obj->IsString()) {
     ExtractStringReferences(entry, String::cast(obj));
-  } else if (obj->IsContext()) {
-    ExtractContextReferences(entry, Context::cast(obj));
+  } else if (obj->IsSymbol()) {
+    ExtractSymbolReferences(entry, Symbol::cast(obj));
   } else if (obj->IsMap()) {
     ExtractMapReferences(entry, Map::cast(obj));
   } else if (obj->IsSharedFunctionInfo()) {
     ExtractSharedFunctionInfoReferences(entry, SharedFunctionInfo::cast(obj));
   } else if (obj->IsScript()) {
     ExtractScriptReferences(entry, Script::cast(obj));
+  } else if (obj->IsAccessorInfo()) {
+    ExtractAccessorInfoReferences(entry, AccessorInfo::cast(obj));
   } else if (obj->IsAccessorPair()) {
     ExtractAccessorPairReferences(entry, AccessorPair::cast(obj));
   } else if (obj->IsCodeCache()) {
@@ -1056,12 +1084,19 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
   } else if (obj->IsAllocationSite()) {
     ExtractAllocationSiteReferences(entry, AllocationSite::cast(obj));
   }
-  SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
+  return true;
+}
+
 
-  // Extract unvisited fields as hidden references and restore tags
-  // of visited fields.
-  IndexedReferencesExtractor refs_extractor(this, obj, entry);
-  obj->Iterate(&refs_extractor);
+bool V8HeapExplorer::ExtractReferencesPass2(int entry, HeapObject* obj) {
+  if (!obj->IsFixedArray()) return false;
+
+  if (obj->IsContext()) {
+    ExtractContextReferences(entry, Context::cast(obj));
+  } else {
+    ExtractFixedArrayReferences(entry, FixedArray::cast(obj));
+  }
+  return true;
 }
 
 
@@ -1080,8 +1115,8 @@ void V8HeapExplorer::ExtractJSObjectReferences(
   ExtractPropertyReferences(js_obj, entry);
   ExtractElementReferences(js_obj, entry);
   ExtractInternalReferences(js_obj, entry);
-  SetPropertyReference(
-      obj, entry, heap_->proto_string(), js_obj->GetPrototype());
+  PrototypeIterator iter(heap_->isolate(), js_obj);
+  SetPropertyReference(obj, entry, heap_->proto_string(), iter.GetCurrent());
   if (obj->IsJSFunction()) {
     JSFunction* js_fun = JSFunction::cast(js_obj);
     Object* proto_or_map = js_fun->prototype_or_initial_map();
@@ -1121,9 +1156,9 @@ void V8HeapExplorer::ExtractJSObjectReferences(
     SetWeakReference(js_fun, entry,
                      "next_function_link", js_fun->next_function_link(),
                      JSFunction::kNextFunctionLinkOffset);
-    STATIC_CHECK(JSFunction::kNextFunctionLinkOffset
+    STATIC_ASSERT(JSFunction::kNextFunctionLinkOffset
                  == JSFunction::kNonWeakFieldsEndOffset);
-    STATIC_CHECK(JSFunction::kNextFunctionLinkOffset + kPointerSize
+    STATIC_ASSERT(JSFunction::kNextFunctionLinkOffset + kPointerSize
                  == JSFunction::kSize);
   } else if (obj->IsGlobalObject()) {
     GlobalObject* global_obj = GlobalObject::cast(obj);
@@ -1137,9 +1172,9 @@ void V8HeapExplorer::ExtractJSObjectReferences(
                          "global_context", global_obj->global_context(),
                          GlobalObject::kGlobalContextOffset);
     SetInternalReference(global_obj, entry,
-                         "global_receiver", global_obj->global_receiver(),
-                         GlobalObject::kGlobalReceiverOffset);
-    STATIC_CHECK(GlobalObject::kHeaderSize - JSObject::kHeaderSize ==
+                         "global_proxy", global_obj->global_proxy(),
+                         GlobalObject::kGlobalProxyOffset);
+    STATIC_ASSERT(GlobalObject::kHeaderSize - JSObject::kHeaderSize ==
                  4 * kPointerSize);
   } else if (obj->IsJSArrayBufferView()) {
     JSArrayBufferView* view = JSArrayBufferView::cast(obj);
@@ -1147,13 +1182,6 @@ void V8HeapExplorer::ExtractJSObjectReferences(
                          JSArrayBufferView::kBufferOffset);
     SetWeakReference(view, entry, "weak_next", view->weak_next(),
                      JSArrayBufferView::kWeakNextOffset);
-  } else if (obj->IsJSArrayBuffer()) {
-    JSArrayBuffer* buffer = JSArrayBuffer::cast(obj);
-    SetWeakReference(buffer, entry, "weak_next", buffer->weak_next(),
-                     JSArrayBuffer::kWeakNextOffset);
-    SetWeakReference(buffer, entry,
-                     "weak_first_view", buffer->weak_first_view(),
-                     JSArrayBuffer::kWeakFirstViewOffset);
   }
   TagObject(js_obj->properties(), "(object properties)");
   SetInternalReference(obj, entry,
@@ -1181,6 +1209,29 @@ void V8HeapExplorer::ExtractStringReferences(int entry, String* string) {
 }
 
 
+void V8HeapExplorer::ExtractSymbolReferences(int entry, Symbol* symbol) {
+  SetInternalReference(symbol, entry,
+                       "name", symbol->name(),
+                       Symbol::kNameOffset);
+}
+
+
+void V8HeapExplorer::ExtractJSCollectionReferences(int entry,
+                                                   JSCollection* collection) {
+  SetInternalReference(collection, entry, "table", collection->table(),
+                       JSCollection::kTableOffset);
+}
+
+
+void V8HeapExplorer::ExtractJSWeakCollectionReferences(
+    int entry, JSWeakCollection* collection) {
+  MarkAsWeakContainer(collection->table());
+  SetInternalReference(collection, entry,
+                       "table", collection->table(),
+                       JSWeakCollection::kTableOffset);
+}
+
+
 void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
   if (context == context->declaration_context()) {
     ScopeInfo* scope_info = context->closure()->shared()->scope_info();
@@ -1204,7 +1255,8 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
   }
 
 #define EXTRACT_CONTEXT_FIELD(index, type, name) \
-  if (Context::index < Context::FIRST_WEAK_SLOT) { \
+  if (Context::index < Context::FIRST_WEAK_SLOT || \
+      Context::index == Context::MAP_CACHE_INDEX) { \
     SetInternalReference(context, entry, #name, context->get(Context::index), \
         FixedArray::OffsetOfElementAt(Context::index)); \
   } else { \
@@ -1228,10 +1280,12 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
     EXTRACT_CONTEXT_FIELD(DEOPTIMIZED_CODE_LIST, unused, deoptimized_code_list);
     EXTRACT_CONTEXT_FIELD(NEXT_CONTEXT_LINK, unused, next_context_link);
 #undef EXTRACT_CONTEXT_FIELD
-    STATIC_CHECK(Context::OPTIMIZED_FUNCTIONS_LIST == Context::FIRST_WEAK_SLOT);
-    STATIC_CHECK(Context::NEXT_CONTEXT_LINK + 1
-                 == Context::NATIVE_CONTEXT_SLOTS);
-    STATIC_CHECK(Context::FIRST_WEAK_SLOT + 5 == Context::NATIVE_CONTEXT_SLOTS);
+    STATIC_ASSERT(Context::OPTIMIZED_FUNCTIONS_LIST ==
+                  Context::FIRST_WEAK_SLOT);
+    STATIC_ASSERT(Context::NEXT_CONTEXT_LINK + 1 ==
+                  Context::NATIVE_CONTEXT_SLOTS);
+    STATIC_ASSERT(Context::FIRST_WEAK_SLOT + 5 ==
+                  Context::NATIVE_CONTEXT_SLOTS);
   }
 }
 
@@ -1244,6 +1298,22 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
     TagObject(back_pointer, "(back pointer)");
     SetInternalReference(transitions, transitions_entry,
                          "back_pointer", back_pointer);
+
+    if (FLAG_collect_maps && map->CanTransition()) {
+      if (!transitions->IsSimpleTransition()) {
+        if (transitions->HasPrototypeTransitions()) {
+          FixedArray* prototype_transitions =
+              transitions->GetPrototypeTransitions();
+          MarkAsWeakContainer(prototype_transitions);
+          TagObject(prototype_transitions, "(prototype transitions");
+          SetInternalReference(transitions, transitions_entry,
+                               "prototype_transitions", prototype_transitions);
+        }
+        // TODO(alph): transitions keys are strong links.
+        MarkAsWeakContainer(transitions);
+      }
+    }
+
     TagObject(transitions, "(transition array)");
     SetInternalReference(map, entry,
                          "transitions", transitions,
@@ -1261,6 +1331,7 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
                        "descriptors", descriptors,
                        Map::kDescriptorsOffset);
 
+  MarkAsWeakContainer(map->code_cache());
   SetInternalReference(map, entry,
                        "code_cache", map->code_cache(),
                        Map::kCodeCacheOffset);
@@ -1270,6 +1341,7 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
                        "constructor", map->constructor(),
                        Map::kConstructorOffset);
   TagObject(map->dependent_code(), "(dependent code)");
+  MarkAsWeakContainer(map->dependent_code());
   SetInternalReference(map, entry,
                        "dependent_code", map->dependent_code(),
                        Map::kDependentCodeOffset);
@@ -1324,9 +1396,9 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
   SetInternalReference(obj, entry,
                        "optimized_code_map", shared->optimized_code_map(),
                        SharedFunctionInfo::kOptimizedCodeMapOffset);
-  SetWeakReference(obj, entry,
-                   "initial_map", shared->initial_map(),
-                   SharedFunctionInfo::kInitialMapOffset);
+  SetInternalReference(obj, entry,
+                       "feedback_vector", shared->feedback_vector(),
+                       SharedFunctionInfo::kFeedbackVectorOffset);
 }
 
 
@@ -1339,9 +1411,6 @@ void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) {
                        "name", script->name(),
                        Script::kNameOffset);
   SetInternalReference(obj, entry,
-                       "data", script->data(),
-                       Script::kDataOffset);
-  SetInternalReference(obj, entry,
                        "context_data", script->context_data(),
                        Script::kContextOffset);
   TagObject(script->line_ends(), "(script line ends)");
@@ -1351,6 +1420,35 @@ void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) {
 }
 
 
+void V8HeapExplorer::ExtractAccessorInfoReferences(
+    int entry, AccessorInfo* accessor_info) {
+  SetInternalReference(accessor_info, entry, "name", accessor_info->name(),
+                       AccessorInfo::kNameOffset);
+  SetInternalReference(accessor_info, entry, "expected_receiver_type",
+                       accessor_info->expected_receiver_type(),
+                       AccessorInfo::kExpectedReceiverTypeOffset);
+  if (accessor_info->IsDeclaredAccessorInfo()) {
+    DeclaredAccessorInfo* declared_accessor_info =
+        DeclaredAccessorInfo::cast(accessor_info);
+    SetInternalReference(declared_accessor_info, entry, "descriptor",
+                         declared_accessor_info->descriptor(),
+                         DeclaredAccessorInfo::kDescriptorOffset);
+  } else if (accessor_info->IsExecutableAccessorInfo()) {
+    ExecutableAccessorInfo* executable_accessor_info =
+        ExecutableAccessorInfo::cast(accessor_info);
+    SetInternalReference(executable_accessor_info, entry, "getter",
+                         executable_accessor_info->getter(),
+                         ExecutableAccessorInfo::kGetterOffset);
+    SetInternalReference(executable_accessor_info, entry, "setter",
+                         executable_accessor_info->setter(),
+                         ExecutableAccessorInfo::kSetterOffset);
+    SetInternalReference(executable_accessor_info, entry, "data",
+                         executable_accessor_info->data(),
+                         ExecutableAccessorInfo::kDataOffset);
+  }
+}
+
+
 void V8HeapExplorer::ExtractAccessorPairReferences(
     int entry, AccessorPair* accessors) {
   SetInternalReference(accessors, entry, "getter", accessors->getter(),
@@ -1381,8 +1479,8 @@ void V8HeapExplorer::TagBuiltinCodeObject(Code* code, const char* name) {
 void V8HeapExplorer::TagCodeObject(Code* code) {
   if (code->kind() == Code::STUB) {
     TagObject(code, names_->GetFormatted(
-        "(%s code)", CodeStub::MajorName(
-            static_cast<CodeStub::Major>(code->major_key()), true)));
+                        "(%s code)", CodeStub::MajorName(
+                                         CodeStub::GetMajorKey(code), true)));
   }
 }
 
@@ -1434,6 +1532,7 @@ void V8HeapExplorer::ExtractPropertyCellReferences(int entry,
   ExtractCellReferences(entry, cell);
   SetInternalReference(cell, entry, "type", cell->type(),
                        PropertyCell::kTypeOffset);
+  MarkAsWeakContainer(cell->dependent_code());
   SetInternalReference(cell, entry, "dependent_code", cell->dependent_code(),
                        PropertyCell::kDependentCodeOffset);
 }
@@ -1445,15 +1544,66 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(int entry,
                        AllocationSite::kTransitionInfoOffset);
   SetInternalReference(site, entry, "nested_site", site->nested_site(),
                        AllocationSite::kNestedSiteOffset);
+  MarkAsWeakContainer(site->dependent_code());
   SetInternalReference(site, entry, "dependent_code", site->dependent_code(),
                        AllocationSite::kDependentCodeOffset);
   // Do not visit weak_next as it is not visited by the StaticVisitor,
   // and we're not very interested in weak_next field here.
-  STATIC_CHECK(AllocationSite::kWeakNextOffset >=
+  STATIC_ASSERT(AllocationSite::kWeakNextOffset >=
                AllocationSite::BodyDescriptor::kEndOffset);
 }
 
 
+class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator {
+ public:
+  JSArrayBufferDataEntryAllocator(size_t size, V8HeapExplorer* explorer)
+      : size_(size)
+      , explorer_(explorer) {
+  }
+  virtual HeapEntry* AllocateEntry(HeapThing ptr) {
+    return explorer_->AddEntry(
+        static_cast<Address>(ptr),
+        HeapEntry::kNative, "system / JSArrayBufferData", size_);
+  }
+ private:
+  size_t size_;
+  V8HeapExplorer* explorer_;
+};
+
+
+void V8HeapExplorer::ExtractJSArrayBufferReferences(
+    int entry, JSArrayBuffer* buffer) {
+  SetWeakReference(buffer, entry, "weak_next", buffer->weak_next(),
+                   JSArrayBuffer::kWeakNextOffset);
+  SetWeakReference(buffer, entry,
+                   "weak_first_view", buffer->weak_first_view(),
+                   JSArrayBuffer::kWeakFirstViewOffset);
+  // Setup a reference to a native memory backing_store object.
+  if (!buffer->backing_store())
+    return;
+  size_t data_size = NumberToSize(heap_->isolate(), buffer->byte_length());
+  JSArrayBufferDataEntryAllocator allocator(data_size, this);
+  HeapEntry* data_entry =
+      filler_->FindOrAddEntry(buffer->backing_store(), &allocator);
+  filler_->SetNamedReference(HeapGraphEdge::kInternal,
+                             entry, "backing_store", data_entry);
+}
+
+
+void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) {
+  bool is_weak = weak_containers_.Contains(array);
+  for (int i = 0, l = array->length(); i < l; ++i) {
+    if (is_weak) {
+      SetWeakReference(array, entry,
+                       i, array->get(i), array->OffsetOfElementAt(i));
+    } else {
+      SetInternalReference(array, entry,
+                           i, array->get(i), array->OffsetOfElementAt(i));
+    }
+  }
+}
+
+
 void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) {
   if (!js_obj->IsJSFunction()) return;
 
@@ -1483,6 +1633,8 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
     for (int i = 0; i < real_size; i++) {
       switch (descs->GetType(i)) {
         case FIELD: {
+          Representation r = descs->GetDetails(i).representation();
+          if (r.IsSmi() || r.IsDouble()) break;
           int index = descs->GetFieldIndex(i);
 
           Name* k = descs->GetKey(i);
@@ -1502,7 +1654,9 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
                   js_obj->GetInObjectPropertyOffset(index));
             }
           } else {
-            Object* value = js_obj->RawFastPropertyAt(index);
+            FieldIndex field_index =
+                FieldIndex::ForDescriptor(js_obj->map(), i);
+            Object* value = js_obj->RawFastPropertyAt(field_index);
             if (k != heap_->hidden_string()) {
               SetPropertyReference(js_obj, entry, k, value);
             } else {
@@ -1523,11 +1677,6 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
               descs->GetKey(i), descs->GetValue(i));
           break;
         case NORMAL:  // only in slow mode
-        case HANDLER:  // only in lookup results, not in descriptors
-        case INTERCEPTOR:  // only in lookup results, not in descriptors
-          break;
-        case TRANSITION:
-        case NONEXISTENT:
           UNREACHABLE();
           break;
       }
@@ -1589,7 +1738,7 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) {
     for (int i = 0; i < length; ++i) {
       Object* k = dictionary->KeyAt(i);
       if (dictionary->IsKey(k)) {
-        ASSERT(k->IsNumber());
+        DCHECK(k->IsNumber());
         uint32_t index = static_cast<uint32_t>(k->Number());
         SetElementReference(js_obj, entry, index, dictionary->ValueAt(i));
       }
@@ -1613,23 +1762,8 @@ String* V8HeapExplorer::GetConstructorName(JSObject* object) {
   if (object->IsJSFunction()) return heap->closure_string();
   String* constructor_name = object->constructor_name();
   if (constructor_name == heap->Object_string()) {
-    // Look up an immediate "constructor" property, if it is a function,
-    // return its name. This is for instances of binding objects, which
-    // have prototype constructor type "Object".
-    Object* constructor_prop = NULL;
-    LookupResult result(heap->isolate());
-    object->LocalLookupRealNamedProperty(heap->constructor_string(), &result);
-    if (!result.IsFound()) return object->constructor_name();
-
-    constructor_prop = result.GetLazyValue();
-    if (constructor_prop->IsJSFunction()) {
-      Object* maybe_name =
-          JSFunction::cast(constructor_prop)->shared()->name();
-      if (maybe_name->IsString()) {
-        String* name = String::cast(maybe_name);
-        if (name->length() > 0) return name;
-      }
-    }
+    // TODO(verwaest): Try to get object.constructor.name in this case.
+    // This requires handlification of the V8HeapExplorer.
   }
   return object->constructor_name();
 }
@@ -1668,11 +1802,8 @@ class RootsReferencesExtractor : public ObjectVisitor {
   void SetCollectingAllReferences() { collecting_all_references_ = true; }
 
   void FillReferences(V8HeapExplorer* explorer) {
-    ASSERT(strong_references_.length() <= all_references_.length());
+    DCHECK(strong_references_.length() <= all_references_.length());
     Builtins* builtins = heap_->isolate()->builtins();
-    for (int i = 0; i < reference_tags_.length(); ++i) {
-      explorer->SetGcRootsReference(reference_tags_[i].tag);
-    }
     int strong_index = 0, all_index = 0, tags_index = 0, builtin_index = 0;
     while (all_index < all_references_.length()) {
       bool is_strong = strong_index < strong_references_.length()
@@ -1682,7 +1813,7 @@ class RootsReferencesExtractor : public ObjectVisitor {
                                       all_references_[all_index]);
       if (reference_tags_[tags_index].tag ==
           VisitorSynchronization::kBuiltins) {
-        ASSERT(all_references_[all_index]->IsCode());
+        DCHECK(all_references_[all_index]->IsCode());
         explorer->TagBuiltinCodeObject(
             Code::cast(all_references_[all_index]),
             builtins->name(builtin_index++));
@@ -1712,19 +1843,43 @@ class RootsReferencesExtractor : public ObjectVisitor {
 
 
 bool V8HeapExplorer::IterateAndExtractReferences(
-    SnapshotFillerInterface* filler) {
+    SnapshotFiller* filler) {
   filler_ = filler;
 
+  // Create references to the synthetic roots.
+  SetRootGcRootsReference();
+  for (int tag = 0; tag < VisitorSynchronization::kNumberOfSyncTags; tag++) {
+    SetGcRootsReference(static_cast<VisitorSynchronization::SyncTag>(tag));
+  }
+
   // Make sure builtin code objects get their builtin tags
   // first. Otherwise a particular JSFunction object could set
   // its custom name to a generic builtin.
-  SetRootGcRootsReference();
   RootsReferencesExtractor extractor(heap_);
   heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG);
   extractor.SetCollectingAllReferences();
   heap_->IterateRoots(&extractor, VISIT_ALL);
   extractor.FillReferences(this);
 
+  // We have to do two passes as sometimes FixedArrays are used
+  // to weakly hold their items, and it's impossible to distinguish
+  // between these cases without processing the array owner first.
+  bool interrupted =
+      IterateAndExtractSinglePass<&V8HeapExplorer::ExtractReferencesPass1>() ||
+      IterateAndExtractSinglePass<&V8HeapExplorer::ExtractReferencesPass2>();
+
+  if (interrupted) {
+    filler_ = NULL;
+    return false;
+  }
+
+  filler_ = NULL;
+  return progress_->ProgressReport(true);
+}
+
+
+template<V8HeapExplorer::ExtractReferencesMethod extractor>
+bool V8HeapExplorer::IterateAndExtractSinglePass() {
   // Now iterate the whole heap.
   bool interrupted = false;
   HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable);
@@ -1732,18 +1887,22 @@ bool V8HeapExplorer::IterateAndExtractReferences(
   for (HeapObject* obj = iterator.next();
        obj != NULL;
        obj = iterator.next(), progress_->ProgressStep()) {
-    if (!interrupted) {
-      ExtractReferences(obj);
-      if (!progress_->ProgressReport(false)) interrupted = true;
+    if (interrupted) continue;
+
+    HeapEntry* heap_entry = GetEntry(obj);
+    int entry = heap_entry->index();
+    if ((this->*extractor)(entry, obj)) {
+      SetInternalReference(obj, entry,
+                           "map", obj->map(), HeapObject::kMapOffset);
+      // Extract unvisited fields as hidden references and restore tags
+      // of visited fields.
+      IndexedReferencesExtractor refs_extractor(this, obj, entry);
+      obj->Iterate(&refs_extractor);
     }
-  }
-  if (interrupted) {
-    filler_ = NULL;
-    return false;
-  }
 
-  filler_ = NULL;
-  return progress_->ProgressReport(true);
+    if (!progress_->ProgressReport(false)) interrupted = true;
+  }
+  return interrupted;
 }
 
 
@@ -1768,7 +1927,7 @@ void V8HeapExplorer::SetContextReference(HeapObject* parent_obj,
                                          String* reference_name,
                                          Object* child_obj,
                                          int field_offset) {
-  ASSERT(parent_entry == GetEntry(parent_obj)->index());
+  DCHECK(parent_entry == GetEntry(parent_obj)->index());
   HeapEntry* child_entry = GetEntry(child_obj);
   if (child_entry != NULL) {
     filler_->SetNamedReference(HeapGraphEdge::kContextVariable,
@@ -1784,7 +1943,7 @@ void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj,
                                             int parent_entry,
                                             const char* reference_name,
                                             Object* child_obj) {
-  ASSERT(parent_entry == GetEntry(parent_obj)->index());
+  DCHECK(parent_entry == GetEntry(parent_obj)->index());
   HeapEntry* child_entry = GetEntry(child_obj);
   if (child_entry != NULL) {
     filler_->SetNamedReference(HeapGraphEdge::kShortcut,
@@ -1799,7 +1958,7 @@ void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
                                          int parent_entry,
                                          int index,
                                          Object* child_obj) {
-  ASSERT(parent_entry == GetEntry(parent_obj)->index());
+  DCHECK(parent_entry == GetEntry(parent_obj)->index());
   HeapEntry* child_entry = GetEntry(child_obj);
   if (child_entry != NULL) {
     filler_->SetIndexedReference(HeapGraphEdge::kElement,
@@ -1815,7 +1974,7 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
                                           const char* reference_name,
                                           Object* child_obj,
                                           int field_offset) {
-  ASSERT(parent_entry == GetEntry(parent_obj)->index());
+  DCHECK(parent_entry == GetEntry(parent_obj)->index());
   HeapEntry* child_entry = GetEntry(child_obj);
   if (child_entry == NULL) return;
   if (IsEssentialObject(child_obj)) {
@@ -1833,7 +1992,7 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
                                           int index,
                                           Object* child_obj,
                                           int field_offset) {
-  ASSERT(parent_entry == GetEntry(parent_obj)->index());
+  DCHECK(parent_entry == GetEntry(parent_obj)->index());
   HeapEntry* child_entry = GetEntry(child_obj);
   if (child_entry == NULL) return;
   if (IsEssentialObject(child_obj)) {
@@ -1850,7 +2009,7 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
                                         int parent_entry,
                                         int index,
                                         Object* child_obj) {
-  ASSERT(parent_entry == GetEntry(parent_obj)->index());
+  DCHECK(parent_entry == GetEntry(parent_obj)->index());
   HeapEntry* child_entry = GetEntry(child_obj);
   if (child_entry != NULL && IsEssentialObject(child_obj)) {
     filler_->SetIndexedReference(HeapGraphEdge::kHidden,
@@ -1866,7 +2025,7 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
                                       const char* reference_name,
                                       Object* child_obj,
                                       int field_offset) {
-  ASSERT(parent_entry == GetEntry(parent_obj)->index());
+  DCHECK(parent_entry == GetEntry(parent_obj)->index());
   HeapEntry* child_entry = GetEntry(child_obj);
   if (child_entry == NULL) return;
   if (IsEssentialObject(child_obj)) {
@@ -1879,13 +2038,31 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
 }
 
 
+void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
+                                      int parent_entry,
+                                      int index,
+                                      Object* child_obj,
+                                      int field_offset) {
+  DCHECK(parent_entry == GetEntry(parent_obj)->index());
+  HeapEntry* child_entry = GetEntry(child_obj);
+  if (child_entry == NULL) return;
+  if (IsEssentialObject(child_obj)) {
+    filler_->SetNamedReference(HeapGraphEdge::kWeak,
+                               parent_entry,
+                               names_->GetFormatted("%d", index),
+                               child_entry);
+  }
+  IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
+}
+
+
 void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
                                           int parent_entry,
                                           Name* reference_name,
                                           Object* child_obj,
                                           const char* name_format_string,
                                           int field_offset) {
-  ASSERT(parent_entry == GetEntry(parent_obj)->index());
+  DCHECK(parent_entry == GetEntry(parent_obj)->index());
   HeapEntry* child_entry = GetEntry(child_obj);
   if (child_entry != NULL) {
     HeapGraphEdge::Type type =
@@ -1917,7 +2094,7 @@ void V8HeapExplorer::SetRootGcRootsReference() {
 
 void V8HeapExplorer::SetUserGlobalReference(Object* child_obj) {
   HeapEntry* child_entry = GetEntry(child_obj);
-  ASSERT(child_entry != NULL);
+  DCHECK(child_entry != NULL);
   filler_->SetNamedAutoIndexReference(
       HeapGraphEdge::kShortcut,
       snapshot_->root()->index(),
@@ -1964,9 +2141,7 @@ void V8HeapExplorer::SetGcSubrootReference(
       GlobalObject* global = context->global_object();
       if (global->IsJSGlobalObject()) {
         bool is_debug_object = false;
-#ifdef ENABLE_DEBUGGER_SUPPORT
         is_debug_object = heap_->isolate()->debug()->IsDebugGlobal(global);
-#endif
         if (!is_debug_object && !user_roots_.Contains(global)) {
           user_roots_.Insert(global);
           SetUserGlobalReference(global);
@@ -2006,6 +2181,13 @@ void V8HeapExplorer::TagObject(Object* obj, const char* tag) {
 }
 
 
+void V8HeapExplorer::MarkAsWeakContainer(Object* object) {
+  if (IsEssentialObject(object) && object->IsFixedArray()) {
+    weak_containers_.Insert(object);
+  }
+}
+
+
 class GlobalObjectsEnumerator : public ObjectVisitor {
  public:
   virtual void VisitPointers(Object** start, Object** end) {
@@ -2104,7 +2286,8 @@ HeapEntry* BasicHeapEntriesAllocator::AllocateEntry(HeapThing ptr) {
       entries_type_,
       name,
       heap_object_map_->GenerateId(info),
-      size != -1 ? static_cast<int>(size) : 0);
+      size != -1 ? static_cast<int>(size) : 0,
+      0);
 }
 
 
@@ -2192,7 +2375,7 @@ void NativeObjectsExplorer::FillImplicitReferences() {
     HeapObject* parent = *group->parent;
     int parent_entry =
         filler_->FindOrAddEntry(parent, native_entries_allocator_)->index();
-    ASSERT(parent_entry != HeapEntry::kNoEntry);
+    DCHECK(parent_entry != HeapEntry::kNoEntry);
     Object*** children = group->children;
     for (size_t j = 0; j < group->length; ++j) {
       Object* child = *children[j];
@@ -2222,7 +2405,7 @@ List<HeapObject*>* NativeObjectsExplorer::GetListMaybeDisposeInfo(
 
 
 bool NativeObjectsExplorer::IterateAndExtractReferences(
-    SnapshotFillerInterface* filler) {
+    SnapshotFiller* filler) {
   filler_ = filler;
   FillRetainedObjects();
   FillImplicitReferences();
@@ -2293,7 +2476,7 @@ void NativeObjectsExplorer::SetNativeRootReference(
     v8::RetainedObjectInfo* info) {
   HeapEntry* child_entry =
       filler_->FindOrAddEntry(info, native_entries_allocator_);
-  ASSERT(child_entry != NULL);
+  DCHECK(child_entry != NULL);
   NativeGroupRetainedObjectInfo* group_info =
       FindOrAddGroupInfo(info->GetGroupLabel());
   HeapEntry* group_entry =
@@ -2308,10 +2491,10 @@ void NativeObjectsExplorer::SetNativeRootReference(
 void NativeObjectsExplorer::SetWrapperNativeReferences(
     HeapObject* wrapper, v8::RetainedObjectInfo* info) {
   HeapEntry* wrapper_entry = filler_->FindEntry(wrapper);
-  ASSERT(wrapper_entry != NULL);
+  DCHECK(wrapper_entry != NULL);
   HeapEntry* info_entry =
       filler_->FindOrAddEntry(info, native_entries_allocator_);
-  ASSERT(info_entry != NULL);
+  DCHECK(info_entry != NULL);
   filler_->SetNamedReference(HeapGraphEdge::kInternal,
                              wrapper_entry->index(),
                              "native",
@@ -2330,7 +2513,7 @@ void NativeObjectsExplorer::SetRootNativeRootsReference() {
         static_cast<NativeGroupRetainedObjectInfo*>(entry->value);
     HeapEntry* group_entry =
         filler_->FindOrAddEntry(group_info, native_entries_allocator_);
-    ASSERT(group_entry != NULL);
+    DCHECK(group_entry != NULL);
     filler_->SetIndexedAutoIndexReference(
         HeapGraphEdge::kElement,
         snapshot_->root()->index(),
@@ -2349,64 +2532,6 @@ void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) {
 }
 
 
-class SnapshotFiller : public SnapshotFillerInterface {
- public:
-  explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries)
-      : snapshot_(snapshot),
-        names_(snapshot->profiler()->names()),
-        entries_(entries) { }
-  HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
-    HeapEntry* entry = allocator->AllocateEntry(ptr);
-    entries_->Pair(ptr, entry->index());
-    return entry;
-  }
-  HeapEntry* FindEntry(HeapThing 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,
-                           int parent,
-                           int index,
-                           HeapEntry* child_entry) {
-    HeapEntry* parent_entry = &snapshot_->entries()[parent];
-    parent_entry->SetIndexedReference(type, index, child_entry);
-  }
-  void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
-                                    int parent,
-                                    HeapEntry* child_entry) {
-    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,
-                         int parent,
-                         const char* reference_name,
-                         HeapEntry* child_entry) {
-    HeapEntry* parent_entry = &snapshot_->entries()[parent];
-    parent_entry->SetNamedReference(type, reference_name, child_entry);
-  }
-  void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
-                                  int parent,
-                                  HeapEntry* child_entry) {
-    HeapEntry* parent_entry = &snapshot_->entries()[parent];
-    int index = parent_entry->children_count() + 1;
-    parent_entry->SetNamedReference(
-        type,
-        names_->GetName(index),
-        child_entry);
-  }
-
- private:
-  HeapSnapshot* snapshot_;
-  StringsStorage* names_;
-  HeapEntriesMap* entries_;
-};
-
-
 HeapSnapshotGenerator::HeapSnapshotGenerator(
     HeapSnapshot* snapshot,
     v8::ActivityControl* control,
@@ -2436,29 +2561,17 @@ bool HeapSnapshotGenerator::GenerateSnapshot() {
 
 #ifdef VERIFY_HEAP
   Heap* debug_heap = heap_;
-  CHECK(!debug_heap->old_data_space()->was_swept_conservatively());
-  CHECK(!debug_heap->old_pointer_space()->was_swept_conservatively());
-  CHECK(!debug_heap->code_space()->was_swept_conservatively());
-  CHECK(!debug_heap->cell_space()->was_swept_conservatively());
-  CHECK(!debug_heap->property_cell_space()->
-        was_swept_conservatively());
-  CHECK(!debug_heap->map_space()->was_swept_conservatively());
-#endif
-
-  // The following code uses heap iterators, so we want the heap to be
-  // stable. It should follow TagGlobalObjects as that can allocate.
-  DisallowHeapAllocation no_alloc;
-
-#ifdef VERIFY_HEAP
   debug_heap->Verify();
 #endif
 
-  SetProgressTotal(1);  // 1 pass.
+  SetProgressTotal(2);  // 2 passes.
 
 #ifdef VERIFY_HEAP
   debug_heap->Verify();
 #endif
 
+  snapshot_->AddSyntheticRootEntries();
+
   if (!FillReferences()) return false;
 
   snapshot_->FillChildren();
@@ -2499,7 +2612,6 @@ void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
 
 bool HeapSnapshotGenerator::FillReferences() {
   SnapshotFiller filler(snapshot_, &entries_);
-  v8_heap_explorer_.AddRootEntries(&filler);
   return v8_heap_explorer_.IterateAndExtractReferences(&filler)
       && dom_explorer_.IterateAndExtractReferences(&filler);
 }
@@ -2524,12 +2636,12 @@ class OutputStreamWriter {
         chunk_(chunk_size_),
         chunk_pos_(0),
         aborted_(false) {
-    ASSERT(chunk_size_ > 0);
+    DCHECK(chunk_size_ > 0);
   }
   bool aborted() { return aborted_; }
   void AddCharacter(char c) {
-    ASSERT(c != '\0');
-    ASSERT(chunk_pos_ < chunk_size_);
+    DCHECK(c != '\0');
+    DCHECK(chunk_pos_ < chunk_size_);
     chunk_[chunk_pos_++] = c;
     MaybeWriteChunk();
   }
@@ -2538,13 +2650,13 @@ class OutputStreamWriter {
   }
   void AddSubstring(const char* s, int n) {
     if (n <= 0) return;
-    ASSERT(static_cast<size_t>(n) <= strlen(s));
+    DCHECK(static_cast<size_t>(n) <= strlen(s));
     const char* s_end = s + n;
     while (s < s_end) {
-      int s_chunk_size = Min(
-          chunk_size_ - chunk_pos_, static_cast<int>(s_end - s));
-      ASSERT(s_chunk_size > 0);
-      OS::MemCopy(chunk_.start() + chunk_pos_, s, s_chunk_size);
+      int s_chunk_size =
+          Min(chunk_size_ - chunk_pos_, static_cast<int>(s_end - s));
+      DCHECK(s_chunk_size > 0);
+      MemCopy(chunk_.start() + chunk_pos_, s, s_chunk_size);
       s += s_chunk_size;
       chunk_pos_ += s_chunk_size;
       MaybeWriteChunk();
@@ -2553,7 +2665,7 @@ class OutputStreamWriter {
   void AddNumber(unsigned n) { AddNumberImpl<unsigned>(n, "%u"); }
   void Finalize() {
     if (aborted_) return;
-    ASSERT(chunk_pos_ < chunk_size_);
+    DCHECK(chunk_pos_ < chunk_size_);
     if (chunk_pos_ != 0) {
       WriteChunk();
     }
@@ -2567,21 +2679,21 @@ class OutputStreamWriter {
     static const int kMaxNumberSize =
         MaxDecimalDigitsIn<sizeof(T)>::kUnsigned + 1;
     if (chunk_size_ - chunk_pos_ >= kMaxNumberSize) {
-      int result = OS::SNPrintF(
+      int result = SNPrintF(
           chunk_.SubVector(chunk_pos_, chunk_size_), format, n);
-      ASSERT(result != -1);
+      DCHECK(result != -1);
       chunk_pos_ += result;
       MaybeWriteChunk();
     } else {
       EmbeddedVector<char, kMaxNumberSize> buffer;
-      int result = OS::SNPrintF(buffer, format, n);
+      int result = SNPrintF(buffer, format, n);
       USE(result);
-      ASSERT(result != -1);
+      DCHECK(result != -1);
       AddString(buffer.start());
     }
   }
   void MaybeWriteChunk() {
-    ASSERT(chunk_pos_ <= chunk_size_);
+    DCHECK(chunk_pos_ <= chunk_size_);
     if (chunk_pos_ == chunk_size_) {
       WriteChunk();
     }
@@ -2603,15 +2715,15 @@ class OutputStreamWriter {
 
 // type, name|index, to_node.
 const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3;
-// type, name, id, self_size, children_index.
-const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 5;
+// type, name, id, self_size, edge_count, trace_node_id.
+const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 6;
 
 void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
   if (AllocationTracker* allocation_tracker =
       snapshot_->profiler()->allocation_tracker()) {
     allocation_tracker->PrepareForSerialization();
   }
-  ASSERT(writer_ == NULL);
+  DCHECK(writer_ == NULL);
   writer_ = new OutputStreamWriter(stream);
   SerializeImpl();
   delete writer_;
@@ -2620,7 +2732,7 @@ void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
 
 
 void HeapSnapshotJSONSerializer::SerializeImpl() {
-  ASSERT(0 == snapshot_->root()->index());
+  DCHECK(0 == snapshot_->root()->index());
   writer_->AddCharacter('{');
   writer_->AddString("\"snapshot\":{");
   SerializeSnapshot();
@@ -2663,9 +2775,26 @@ int HeapSnapshotJSONSerializer::GetStringId(const char* s) {
 }
 
 
-static int utoa(unsigned value, const Vector<char>& buffer, int buffer_pos) {
+namespace {
+
+template<size_t size> struct ToUnsigned;
+
+template<> struct ToUnsigned<4> {
+  typedef uint32_t Type;
+};
+
+template<> struct ToUnsigned<8> {
+  typedef uint64_t Type;
+};
+
+}  // namespace
+
+
+template<typename T>
+static int utoa_impl(T value, const Vector<char>& buffer, int buffer_pos) {
+  STATIC_ASSERT(static_cast<T>(-1) > 0);  // Check that T is unsigned
   int number_of_digits = 0;
-  unsigned t = value;
+  T t = value;
   do {
     ++number_of_digits;
   } while (t /= 10);
@@ -2673,7 +2802,7 @@ static int utoa(unsigned value, const Vector<char>& buffer, int buffer_pos) {
   buffer_pos += number_of_digits;
   int result = buffer_pos;
   do {
-    int last_digit = value % 10;
+    int last_digit = static_cast<int>(value % 10);
     buffer[--buffer_pos] = '0' + last_digit;
     value /= 10;
   } while (value);
@@ -2681,6 +2810,14 @@ static int utoa(unsigned value, const Vector<char>& buffer, int buffer_pos) {
 }
 
 
+template<typename T>
+static int utoa(T value, const Vector<char>& buffer, int buffer_pos) {
+  typename ToUnsigned<sizeof(value)>::Type unsigned_value = value;
+  STATIC_ASSERT(sizeof(value) == sizeof(unsigned_value));
+  return utoa_impl(unsigned_value, buffer, buffer_pos);
+}
+
+
 void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
                                                bool first_edge) {
   // The buffer needs space for 3 unsigned ints, 3 commas, \n and \0
@@ -2708,7 +2845,7 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
 void HeapSnapshotJSONSerializer::SerializeEdges() {
   List<HeapGraphEdge*>& edges = snapshot_->children();
   for (int i = 0; i < edges.length(); ++i) {
-    ASSERT(i == 0 ||
+    DCHECK(i == 0 ||
            edges[i - 1]->from()->index() <= edges[i]->from()->index());
     SerializeEdge(edges[i], i == 0);
     if (writer_->aborted()) return;
@@ -2717,10 +2854,11 @@ void HeapSnapshotJSONSerializer::SerializeEdges() {
 
 
 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
-  // The buffer needs space for 5 unsigned ints, 5 commas, \n and \0
+  // The buffer needs space for 4 unsigned ints, 1 size_t, 5 commas, \n and \0
   static const int kBufferSize =
       5 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
-      + 5 + 1 + 1;
+      + MaxDecimalDigitsIn<sizeof(size_t)>::kUnsigned  // NOLINT
+      + 6 + 1 + 1;
   EmbeddedVector<char, kBufferSize> buffer;
   int buffer_pos = 0;
   if (entry_index(entry) != 0) {
@@ -2735,6 +2873,8 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
   buffer_pos = utoa(entry->self_size(), buffer, buffer_pos);
   buffer[buffer_pos++] = ',';
   buffer_pos = utoa(entry->children_count(), buffer, buffer_pos);
+  buffer[buffer_pos++] = ',';
+  buffer_pos = utoa(entry->trace_node_id(), buffer, buffer_pos);
   buffer[buffer_pos++] = '\n';
   buffer[buffer_pos++] = '\0';
   writer_->AddString(buffer.start());
@@ -2768,7 +2908,8 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
         JSON_S("name") ","
         JSON_S("id") ","
         JSON_S("self_size") ","
-        JSON_S("edge_count")) ","
+        JSON_S("edge_count") ","
+        JSON_S("trace_node_id")) ","
     JSON_S("node_types") ":" JSON_A(
         JSON_A(
             JSON_S("hidden") ","
@@ -2813,7 +2954,7 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
         JSON_S("column")) ","
     JSON_S("trace_node_fields") ":" JSON_A(
         JSON_S("id") ","
-        JSON_S("function_id") ","
+        JSON_S("function_info_index") ","
         JSON_S("count") ","
         JSON_S("size") ","
         JSON_S("children"))));
@@ -2828,7 +2969,7 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
   uint32_t count = 0;
   AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker();
   if (tracker) {
-    count = tracker->id_to_function_info()->occupancy();
+    count = tracker->function_info_list().length();
   }
   writer_->AddNumber(count);
 }
@@ -2861,7 +3002,7 @@ void HeapSnapshotJSONSerializer::SerializeTraceNode(AllocationTraceNode* node) {
   int buffer_pos = 0;
   buffer_pos = utoa(node->id(), buffer, buffer_pos);
   buffer[buffer_pos++] = ',';
-  buffer_pos = utoa(node->function_id(), buffer, buffer_pos);
+  buffer_pos = utoa(node->function_info_index(), buffer, buffer_pos);
   buffer[buffer_pos++] = ',';
   buffer_pos = utoa(node->allocation_count(), buffer, buffer_pos);
   buffer[buffer_pos++] = ',';
@@ -2888,7 +3029,7 @@ static int SerializePosition(int position, const Vector<char>& buffer,
   if (position == -1) {
     buffer[buffer_pos++] = '0';
   } else {
-    ASSERT(position >= 0);
+    DCHECK(position >= 0);
     buffer_pos = utoa(static_cast<unsigned>(position + 1), buffer, buffer_pos);
   }
   return buffer_pos;
@@ -2903,22 +3044,18 @@ void HeapSnapshotJSONSerializer::SerializeTraceNodeInfos() {
       6 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
       + 6 + 1 + 1;
   EmbeddedVector<char, kBufferSize> buffer;
-  HashMap* id_to_function_info = tracker->id_to_function_info();
+  const List<AllocationTracker::FunctionInfo*>& list =
+      tracker->function_info_list();
   bool first_entry = true;
-  for (HashMap::Entry* p = id_to_function_info->Start();
-       p != NULL;
-       p = id_to_function_info->Next(p)) {
-    SnapshotObjectId id =
-        static_cast<SnapshotObjectId>(reinterpret_cast<intptr_t>(p->key));
-    AllocationTracker::FunctionInfo* info =
-        reinterpret_cast<AllocationTracker::FunctionInfo* >(p->value);
+  for (int i = 0; i < list.length(); i++) {
+    AllocationTracker::FunctionInfo* info = list[i];
     int buffer_pos = 0;
     if (first_entry) {
       first_entry = false;
     } else {
       buffer[buffer_pos++] = ',';
     }
-    buffer_pos = utoa(id, buffer, buffer_pos);
+    buffer_pos = utoa(info->function_id, buffer, buffer_pos);
     buffer[buffer_pos++] = ',';
     buffer_pos = utoa(GetStringId(info->name), buffer, buffer_pos);
     buffer[buffer_pos++] = ',';
@@ -2976,7 +3113,7 @@ void HeapSnapshotJSONSerializer::SerializeString(const unsigned char* s) {
           unibrow::uchar c = unibrow::Utf8::CalculateValue(s, length, &cursor);
           if (c != unibrow::Utf8::kBadChar) {
             WriteUChar(writer_, c);
-            ASSERT(cursor != 0);
+            DCHECK(cursor != 0);
             s += cursor - 1;
           } else {
             writer_->AddCharacter('?');