Home | History | Annotate | Download | only in src
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #include "heap-snapshot-generator-inl.h"
     31 
     32 #include "allocation-tracker.h"
     33 #include "code-stubs.h"
     34 #include "heap-profiler.h"
     35 #include "debug.h"
     36 #include "types.h"
     37 
     38 namespace v8 {
     39 namespace internal {
     40 
     41 
     42 HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to)
     43     : type_(type),
     44       from_index_(from),
     45       to_index_(to),
     46       name_(name) {
     47   ASSERT(type == kContextVariable
     48       || type == kProperty
     49       || type == kInternal
     50       || type == kShortcut);
     51 }
     52 
     53 
     54 HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to)
     55     : type_(type),
     56       from_index_(from),
     57       to_index_(to),
     58       index_(index) {
     59   ASSERT(type == kElement || type == kHidden || type == kWeak);
     60 }
     61 
     62 
     63 void HeapGraphEdge::ReplaceToIndexWithEntry(HeapSnapshot* snapshot) {
     64   to_entry_ = &snapshot->entries()[to_index_];
     65 }
     66 
     67 
     68 const int HeapEntry::kNoEntry = -1;
     69 
     70 HeapEntry::HeapEntry(HeapSnapshot* snapshot,
     71                      Type type,
     72                      const char* name,
     73                      SnapshotObjectId id,
     74                      int self_size)
     75     : type_(type),
     76       children_count_(0),
     77       children_index_(-1),
     78       self_size_(self_size),
     79       id_(id),
     80       snapshot_(snapshot),
     81       name_(name) { }
     82 
     83 
     84 void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
     85                                   const char* name,
     86                                   HeapEntry* entry) {
     87   HeapGraphEdge edge(type, name, this->index(), entry->index());
     88   snapshot_->edges().Add(edge);
     89   ++children_count_;
     90 }
     91 
     92 
     93 void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
     94                                     int index,
     95                                     HeapEntry* entry) {
     96   HeapGraphEdge edge(type, index, this->index(), entry->index());
     97   snapshot_->edges().Add(edge);
     98   ++children_count_;
     99 }
    100 
    101 
    102 Handle<HeapObject> HeapEntry::GetHeapObject() {
    103   return snapshot_->profiler()->FindHeapObjectById(id());
    104 }
    105 
    106 
    107 void HeapEntry::Print(
    108     const char* prefix, const char* edge_name, int max_depth, int indent) {
    109   STATIC_CHECK(sizeof(unsigned) == sizeof(id()));
    110   OS::Print("%6d @%6u %*c %s%s: ",
    111             self_size(), id(), indent, ' ', prefix, edge_name);
    112   if (type() != kString) {
    113     OS::Print("%s %.40s\n", TypeAsString(), name_);
    114   } else {
    115     OS::Print("\"");
    116     const char* c = name_;
    117     while (*c && (c - name_) <= 40) {
    118       if (*c != '\n')
    119         OS::Print("%c", *c);
    120       else
    121         OS::Print("\\n");
    122       ++c;
    123     }
    124     OS::Print("\"\n");
    125   }
    126   if (--max_depth == 0) return;
    127   Vector<HeapGraphEdge*> ch = children();
    128   for (int i = 0; i < ch.length(); ++i) {
    129     HeapGraphEdge& edge = *ch[i];
    130     const char* edge_prefix = "";
    131     EmbeddedVector<char, 64> index;
    132     const char* edge_name = index.start();
    133     switch (edge.type()) {
    134       case HeapGraphEdge::kContextVariable:
    135         edge_prefix = "#";
    136         edge_name = edge.name();
    137         break;
    138       case HeapGraphEdge::kElement:
    139         OS::SNPrintF(index, "%d", edge.index());
    140         break;
    141       case HeapGraphEdge::kInternal:
    142         edge_prefix = "$";
    143         edge_name = edge.name();
    144         break;
    145       case HeapGraphEdge::kProperty:
    146         edge_name = edge.name();
    147         break;
    148       case HeapGraphEdge::kHidden:
    149         edge_prefix = "$";
    150         OS::SNPrintF(index, "%d", edge.index());
    151         break;
    152       case HeapGraphEdge::kShortcut:
    153         edge_prefix = "^";
    154         edge_name = edge.name();
    155         break;
    156       case HeapGraphEdge::kWeak:
    157         edge_prefix = "w";
    158         OS::SNPrintF(index, "%d", edge.index());
    159         break;
    160       default:
    161         OS::SNPrintF(index, "!!! unknown edge type: %d ", edge.type());
    162     }
    163     edge.to()->Print(edge_prefix, edge_name, max_depth, indent + 2);
    164   }
    165 }
    166 
    167 
    168 const char* HeapEntry::TypeAsString() {
    169   switch (type()) {
    170     case kHidden: return "/hidden/";
    171     case kObject: return "/object/";
    172     case kClosure: return "/closure/";
    173     case kString: return "/string/";
    174     case kCode: return "/code/";
    175     case kArray: return "/array/";
    176     case kRegExp: return "/regexp/";
    177     case kHeapNumber: return "/number/";
    178     case kNative: return "/native/";
    179     case kSynthetic: return "/synthetic/";
    180     case kConsString: return "/concatenated string/";
    181     case kSlicedString: return "/sliced string/";
    182     default: return "???";
    183   }
    184 }
    185 
    186 
    187 // It is very important to keep objects that form a heap snapshot
    188 // as small as possible.
    189 namespace {  // Avoid littering the global namespace.
    190 
    191 template <size_t ptr_size> struct SnapshotSizeConstants;
    192 
    193 template <> struct SnapshotSizeConstants<4> {
    194   static const int kExpectedHeapGraphEdgeSize = 12;
    195   static const int kExpectedHeapEntrySize = 24;
    196 };
    197 
    198 template <> struct SnapshotSizeConstants<8> {
    199   static const int kExpectedHeapGraphEdgeSize = 24;
    200   static const int kExpectedHeapEntrySize = 32;
    201 };
    202 
    203 }  // namespace
    204 
    205 HeapSnapshot::HeapSnapshot(HeapProfiler* profiler,
    206                            const char* title,
    207                            unsigned uid)
    208     : profiler_(profiler),
    209       title_(title),
    210       uid_(uid),
    211       root_index_(HeapEntry::kNoEntry),
    212       gc_roots_index_(HeapEntry::kNoEntry),
    213       natives_root_index_(HeapEntry::kNoEntry),
    214       max_snapshot_js_object_id_(0) {
    215   STATIC_CHECK(
    216       sizeof(HeapGraphEdge) ==
    217       SnapshotSizeConstants<kPointerSize>::kExpectedHeapGraphEdgeSize);
    218   STATIC_CHECK(
    219       sizeof(HeapEntry) ==
    220       SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize);
    221   for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) {
    222     gc_subroot_indexes_[i] = HeapEntry::kNoEntry;
    223   }
    224 }
    225 
    226 
    227 void HeapSnapshot::Delete() {
    228   profiler_->RemoveSnapshot(this);
    229   delete this;
    230 }
    231 
    232 
    233 void HeapSnapshot::RememberLastJSObjectId() {
    234   max_snapshot_js_object_id_ = profiler_->heap_object_map()->last_assigned_id();
    235 }
    236 
    237 
    238 HeapEntry* HeapSnapshot::AddRootEntry() {
    239   ASSERT(root_index_ == HeapEntry::kNoEntry);
    240   ASSERT(entries_.is_empty());  // Root entry must be the first one.
    241   HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
    242                               "",
    243                               HeapObjectsMap::kInternalRootObjectId,
    244                               0);
    245   root_index_ = entry->index();
    246   ASSERT(root_index_ == 0);
    247   return entry;
    248 }
    249 
    250 
    251 HeapEntry* HeapSnapshot::AddGcRootsEntry() {
    252   ASSERT(gc_roots_index_ == HeapEntry::kNoEntry);
    253   HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
    254                               "(GC roots)",
    255                               HeapObjectsMap::kGcRootsObjectId,
    256                               0);
    257   gc_roots_index_ = entry->index();
    258   return entry;
    259 }
    260 
    261 
    262 HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag) {
    263   ASSERT(gc_subroot_indexes_[tag] == HeapEntry::kNoEntry);
    264   ASSERT(0 <= tag && tag < VisitorSynchronization::kNumberOfSyncTags);
    265   HeapEntry* entry = AddEntry(
    266       HeapEntry::kSynthetic,
    267       VisitorSynchronization::kTagNames[tag],
    268       HeapObjectsMap::GetNthGcSubrootId(tag),
    269       0);
    270   gc_subroot_indexes_[tag] = entry->index();
    271   return entry;
    272 }
    273 
    274 
    275 HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
    276                                   const char* name,
    277                                   SnapshotObjectId id,
    278                                   int size) {
    279   HeapEntry entry(this, type, name, id, size);
    280   entries_.Add(entry);
    281   return &entries_.last();
    282 }
    283 
    284 
    285 void HeapSnapshot::FillChildren() {
    286   ASSERT(children().is_empty());
    287   children().Allocate(edges().length());
    288   int children_index = 0;
    289   for (int i = 0; i < entries().length(); ++i) {
    290     HeapEntry* entry = &entries()[i];
    291     children_index = entry->set_children_index(children_index);
    292   }
    293   ASSERT(edges().length() == children_index);
    294   for (int i = 0; i < edges().length(); ++i) {
    295     HeapGraphEdge* edge = &edges()[i];
    296     edge->ReplaceToIndexWithEntry(this);
    297     edge->from()->add_child(edge);
    298   }
    299 }
    300 
    301 
    302 class FindEntryById {
    303  public:
    304   explicit FindEntryById(SnapshotObjectId id) : id_(id) { }
    305   int operator()(HeapEntry* const* entry) {
    306     if ((*entry)->id() == id_) return 0;
    307     return (*entry)->id() < id_ ? -1 : 1;
    308   }
    309  private:
    310   SnapshotObjectId id_;
    311 };
    312 
    313 
    314 HeapEntry* HeapSnapshot::GetEntryById(SnapshotObjectId id) {
    315   List<HeapEntry*>* entries_by_id = GetSortedEntriesList();
    316   // Perform a binary search by id.
    317   int index = SortedListBSearch(*entries_by_id, FindEntryById(id));
    318   if (index == -1)
    319     return NULL;
    320   return entries_by_id->at(index);
    321 }
    322 
    323 
    324 template<class T>
    325 static int SortByIds(const T* entry1_ptr,
    326                      const T* entry2_ptr) {
    327   if ((*entry1_ptr)->id() == (*entry2_ptr)->id()) return 0;
    328   return (*entry1_ptr)->id() < (*entry2_ptr)->id() ? -1 : 1;
    329 }
    330 
    331 
    332 List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() {
    333   if (sorted_entries_.is_empty()) {
    334     sorted_entries_.Allocate(entries_.length());
    335     for (int i = 0; i < entries_.length(); ++i) {
    336       sorted_entries_[i] = &entries_[i];
    337     }
    338     sorted_entries_.Sort(SortByIds);
    339   }
    340   return &sorted_entries_;
    341 }
    342 
    343 
    344 void HeapSnapshot::Print(int max_depth) {
    345   root()->Print("", "", max_depth, 0);
    346 }
    347 
    348 
    349 size_t HeapSnapshot::RawSnapshotSize() const {
    350   return
    351       sizeof(*this) +
    352       GetMemoryUsedByList(entries_) +
    353       GetMemoryUsedByList(edges_) +
    354       GetMemoryUsedByList(children_) +
    355       GetMemoryUsedByList(sorted_entries_);
    356 }
    357 
    358 
    359 // We split IDs on evens for embedder objects (see
    360 // HeapObjectsMap::GenerateId) and odds for native objects.
    361 const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = 1;
    362 const SnapshotObjectId HeapObjectsMap::kGcRootsObjectId =
    363     HeapObjectsMap::kInternalRootObjectId + HeapObjectsMap::kObjectIdStep;
    364 const SnapshotObjectId HeapObjectsMap::kGcRootsFirstSubrootId =
    365     HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep;
    366 const SnapshotObjectId HeapObjectsMap::kFirstAvailableObjectId =
    367     HeapObjectsMap::kGcRootsFirstSubrootId +
    368     VisitorSynchronization::kNumberOfSyncTags * HeapObjectsMap::kObjectIdStep;
    369 
    370 
    371 static bool AddressesMatch(void* key1, void* key2) {
    372   return key1 == key2;
    373 }
    374 
    375 
    376 HeapObjectsMap::HeapObjectsMap(Heap* heap)
    377     : next_id_(kFirstAvailableObjectId),
    378       entries_map_(AddressesMatch),
    379       heap_(heap) {
    380   // This dummy element solves a problem with entries_map_.
    381   // When we do lookup in HashMap we see no difference between two cases:
    382   // it has an entry with NULL as the value or it has created
    383   // a new entry on the fly with NULL as the default value.
    384   // With such dummy element we have a guaranty that all entries_map_ entries
    385   // will have the value field grater than 0.
    386   // This fact is using in MoveObject method.
    387   entries_.Add(EntryInfo(0, NULL, 0));
    388 }
    389 
    390 
    391 void HeapObjectsMap::MoveObject(Address from, Address to, int object_size) {
    392   ASSERT(to != NULL);
    393   ASSERT(from != NULL);
    394   if (from == to) return;
    395   void* from_value = entries_map_.Remove(from, ComputePointerHash(from));
    396   if (from_value == NULL) {
    397     // It may occur that some untracked object moves to an address X and there
    398     // is a tracked object at that address. In this case we should remove the
    399     // entry as we know that the object has died.
    400     void* to_value = entries_map_.Remove(to, ComputePointerHash(to));
    401     if (to_value != NULL) {
    402       int to_entry_info_index =
    403           static_cast<int>(reinterpret_cast<intptr_t>(to_value));
    404       entries_.at(to_entry_info_index).addr = NULL;
    405     }
    406   } else {
    407     HashMap::Entry* to_entry = entries_map_.Lookup(to, ComputePointerHash(to),
    408                                                    true);
    409     if (to_entry->value != NULL) {
    410       // We found the existing entry with to address for an old object.
    411       // Without this operation we will have two EntryInfo's with the same
    412       // value in addr field. It is bad because later at RemoveDeadEntries
    413       // one of this entry will be removed with the corresponding entries_map_
    414       // entry.
    415       int to_entry_info_index =
    416           static_cast<int>(reinterpret_cast<intptr_t>(to_entry->value));
    417       entries_.at(to_entry_info_index).addr = NULL;
    418     }
    419     int from_entry_info_index =
    420         static_cast<int>(reinterpret_cast<intptr_t>(from_value));
    421     entries_.at(from_entry_info_index).addr = to;
    422     // Size of an object can change during its life, so to keep information
    423     // about the object in entries_ consistent, we have to adjust size when the
    424     // object is migrated.
    425     if (FLAG_heap_profiler_trace_objects) {
    426       PrintF("Move object from %p to %p old size %6d new size %6d\n",
    427              from,
    428              to,
    429              entries_.at(from_entry_info_index).size,
    430              object_size);
    431     }
    432     entries_.at(from_entry_info_index).size = object_size;
    433     to_entry->value = from_value;
    434   }
    435 }
    436 
    437 
    438 void HeapObjectsMap::UpdateObjectSize(Address addr, int size) {
    439   FindOrAddEntry(addr, size, false);
    440 }
    441 
    442 
    443 SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) {
    444   HashMap::Entry* entry = entries_map_.Lookup(addr, ComputePointerHash(addr),
    445                                               false);
    446   if (entry == NULL) return 0;
    447   int entry_index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
    448   EntryInfo& entry_info = entries_.at(entry_index);
    449   ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
    450   return entry_info.id;
    451 }
    452 
    453 
    454 SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr,
    455                                                 unsigned int size,
    456                                                 bool accessed) {
    457   ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
    458   HashMap::Entry* entry = entries_map_.Lookup(addr, ComputePointerHash(addr),
    459                                               true);
    460   if (entry->value != NULL) {
    461     int entry_index =
    462         static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
    463     EntryInfo& entry_info = entries_.at(entry_index);
    464     entry_info.accessed = accessed;
    465     if (FLAG_heap_profiler_trace_objects) {
    466       PrintF("Update object size : %p with old size %d and new size %d\n",
    467              addr,
    468              entry_info.size,
    469              size);
    470     }
    471     entry_info.size = size;
    472     return entry_info.id;
    473   }
    474   entry->value = reinterpret_cast<void*>(entries_.length());
    475   SnapshotObjectId id = next_id_;
    476   next_id_ += kObjectIdStep;
    477   entries_.Add(EntryInfo(id, addr, size, accessed));
    478   ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy());
    479   return id;
    480 }
    481 
    482 
    483 void HeapObjectsMap::StopHeapObjectsTracking() {
    484   time_intervals_.Clear();
    485 }
    486 
    487 
    488 void HeapObjectsMap::UpdateHeapObjectsMap() {
    489   if (FLAG_heap_profiler_trace_objects) {
    490     PrintF("Begin HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n",
    491            entries_map_.occupancy());
    492   }
    493   heap_->CollectAllGarbage(Heap::kMakeHeapIterableMask,
    494                           "HeapObjectsMap::UpdateHeapObjectsMap");
    495   HeapIterator iterator(heap_);
    496   for (HeapObject* obj = iterator.next();
    497        obj != NULL;
    498        obj = iterator.next()) {
    499     FindOrAddEntry(obj->address(), obj->Size());
    500     if (FLAG_heap_profiler_trace_objects) {
    501       PrintF("Update object      : %p %6d. Next address is %p\n",
    502              obj->address(),
    503              obj->Size(),
    504              obj->address() + obj->Size());
    505     }
    506   }
    507   RemoveDeadEntries();
    508   if (FLAG_heap_profiler_trace_objects) {
    509     PrintF("End HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n",
    510            entries_map_.occupancy());
    511   }
    512 }
    513 
    514 
    515 namespace {
    516 
    517 
    518 struct HeapObjectInfo {
    519   HeapObjectInfo(HeapObject* obj, int expected_size)
    520     : obj(obj),
    521       expected_size(expected_size) {
    522   }
    523 
    524   HeapObject* obj;
    525   int expected_size;
    526 
    527   bool IsValid() const { return expected_size == obj->Size(); }
    528 
    529   void Print() const {
    530     if (expected_size == 0) {
    531       PrintF("Untracked object   : %p %6d. Next address is %p\n",
    532              obj->address(),
    533              obj->Size(),
    534              obj->address() + obj->Size());
    535     } else if (obj->Size() != expected_size) {
    536       PrintF("Wrong size %6d: %p %6d. Next address is %p\n",
    537              expected_size,
    538              obj->address(),
    539              obj->Size(),
    540              obj->address() + obj->Size());
    541     } else {
    542       PrintF("Good object      : %p %6d. Next address is %p\n",
    543              obj->address(),
    544              expected_size,
    545              obj->address() + obj->Size());
    546     }
    547   }
    548 };
    549 
    550 
    551 static int comparator(const HeapObjectInfo* a, const HeapObjectInfo* b) {
    552   if (a->obj < b->obj) return -1;
    553   if (a->obj > b->obj) return 1;
    554   return 0;
    555 }
    556 
    557 
    558 }  // namespace
    559 
    560 
    561 int HeapObjectsMap::FindUntrackedObjects() {
    562   List<HeapObjectInfo> heap_objects(1000);
    563 
    564   HeapIterator iterator(heap_);
    565   int untracked = 0;
    566   for (HeapObject* obj = iterator.next();
    567        obj != NULL;
    568        obj = iterator.next()) {
    569     HashMap::Entry* entry = entries_map_.Lookup(
    570       obj->address(), ComputePointerHash(obj->address()), false);
    571     if (entry == NULL) {
    572       ++untracked;
    573       if (FLAG_heap_profiler_trace_objects) {
    574         heap_objects.Add(HeapObjectInfo(obj, 0));
    575       }
    576     } else {
    577       int entry_index = static_cast<int>(
    578           reinterpret_cast<intptr_t>(entry->value));
    579       EntryInfo& entry_info = entries_.at(entry_index);
    580       if (FLAG_heap_profiler_trace_objects) {
    581         heap_objects.Add(HeapObjectInfo(obj,
    582                          static_cast<int>(entry_info.size)));
    583         if (obj->Size() != static_cast<int>(entry_info.size))
    584           ++untracked;
    585       } else {
    586         CHECK_EQ(obj->Size(), static_cast<int>(entry_info.size));
    587       }
    588     }
    589   }
    590   if (FLAG_heap_profiler_trace_objects) {
    591     PrintF("\nBegin HeapObjectsMap::FindUntrackedObjects. %d entries in map.\n",
    592            entries_map_.occupancy());
    593     heap_objects.Sort(comparator);
    594     int last_printed_object = -1;
    595     bool print_next_object = false;
    596     for (int i = 0; i < heap_objects.length(); ++i) {
    597       const HeapObjectInfo& object_info = heap_objects[i];
    598       if (!object_info.IsValid()) {
    599         ++untracked;
    600         if (last_printed_object != i - 1) {
    601           if (i > 0) {
    602             PrintF("%d objects were skipped\n", i - 1 - last_printed_object);
    603             heap_objects[i - 1].Print();
    604           }
    605         }
    606         object_info.Print();
    607         last_printed_object = i;
    608         print_next_object = true;
    609       } else if (print_next_object) {
    610         object_info.Print();
    611         print_next_object = false;
    612         last_printed_object = i;
    613       }
    614     }
    615     if (last_printed_object < heap_objects.length() - 1) {
    616       PrintF("Last %d objects were skipped\n",
    617              heap_objects.length() - 1 - last_printed_object);
    618     }
    619     PrintF("End HeapObjectsMap::FindUntrackedObjects. %d entries in map.\n\n",
    620            entries_map_.occupancy());
    621   }
    622   return untracked;
    623 }
    624 
    625 
    626 SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) {
    627   UpdateHeapObjectsMap();
    628   time_intervals_.Add(TimeInterval(next_id_));
    629   int prefered_chunk_size = stream->GetChunkSize();
    630   List<v8::HeapStatsUpdate> stats_buffer;
    631   ASSERT(!entries_.is_empty());
    632   EntryInfo* entry_info = &entries_.first();
    633   EntryInfo* end_entry_info = &entries_.last() + 1;
    634   for (int time_interval_index = 0;
    635        time_interval_index < time_intervals_.length();
    636        ++time_interval_index) {
    637     TimeInterval& time_interval = time_intervals_[time_interval_index];
    638     SnapshotObjectId time_interval_id = time_interval.id;
    639     uint32_t entries_size = 0;
    640     EntryInfo* start_entry_info = entry_info;
    641     while (entry_info < end_entry_info && entry_info->id < time_interval_id) {
    642       entries_size += entry_info->size;
    643       ++entry_info;
    644     }
    645     uint32_t entries_count =
    646         static_cast<uint32_t>(entry_info - start_entry_info);
    647     if (time_interval.count != entries_count ||
    648         time_interval.size != entries_size) {
    649       stats_buffer.Add(v8::HeapStatsUpdate(
    650           time_interval_index,
    651           time_interval.count = entries_count,
    652           time_interval.size = entries_size));
    653       if (stats_buffer.length() >= prefered_chunk_size) {
    654         OutputStream::WriteResult result = stream->WriteHeapStatsChunk(
    655             &stats_buffer.first(), stats_buffer.length());
    656         if (result == OutputStream::kAbort) return last_assigned_id();
    657         stats_buffer.Clear();
    658       }
    659     }
    660   }
    661   ASSERT(entry_info == end_entry_info);
    662   if (!stats_buffer.is_empty()) {
    663     OutputStream::WriteResult result = stream->WriteHeapStatsChunk(
    664         &stats_buffer.first(), stats_buffer.length());
    665     if (result == OutputStream::kAbort) return last_assigned_id();
    666   }
    667   stream->EndOfStream();
    668   return last_assigned_id();
    669 }
    670 
    671 
    672 void HeapObjectsMap::RemoveDeadEntries() {
    673   ASSERT(entries_.length() > 0 &&
    674          entries_.at(0).id == 0 &&
    675          entries_.at(0).addr == NULL);
    676   int first_free_entry = 1;
    677   for (int i = 1; i < entries_.length(); ++i) {
    678     EntryInfo& entry_info = entries_.at(i);
    679     if (entry_info.accessed) {
    680       if (first_free_entry != i) {
    681         entries_.at(first_free_entry) = entry_info;
    682       }
    683       entries_.at(first_free_entry).accessed = false;
    684       HashMap::Entry* entry = entries_map_.Lookup(
    685           entry_info.addr, ComputePointerHash(entry_info.addr), false);
    686       ASSERT(entry);
    687       entry->value = reinterpret_cast<void*>(first_free_entry);
    688       ++first_free_entry;
    689     } else {
    690       if (entry_info.addr) {
    691         entries_map_.Remove(entry_info.addr,
    692                             ComputePointerHash(entry_info.addr));
    693       }
    694     }
    695   }
    696   entries_.Rewind(first_free_entry);
    697   ASSERT(static_cast<uint32_t>(entries_.length()) - 1 ==
    698          entries_map_.occupancy());
    699 }
    700 
    701 
    702 SnapshotObjectId HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) {
    703   SnapshotObjectId id = static_cast<SnapshotObjectId>(info->GetHash());
    704   const char* label = info->GetLabel();
    705   id ^= StringHasher::HashSequentialString(label,
    706                                            static_cast<int>(strlen(label)),
    707                                            heap_->HashSeed());
    708   intptr_t element_count = info->GetElementCount();
    709   if (element_count != -1)
    710     id ^= ComputeIntegerHash(static_cast<uint32_t>(element_count),
    711                              v8::internal::kZeroHashSeed);
    712   return id << 1;
    713 }
    714 
    715 
    716 size_t HeapObjectsMap::GetUsedMemorySize() const {
    717   return
    718       sizeof(*this) +
    719       sizeof(HashMap::Entry) * entries_map_.capacity() +
    720       GetMemoryUsedByList(entries_) +
    721       GetMemoryUsedByList(time_intervals_);
    722 }
    723 
    724 
    725 HeapEntriesMap::HeapEntriesMap()
    726     : entries_(HeapThingsMatch) {
    727 }
    728 
    729 
    730 int HeapEntriesMap::Map(HeapThing thing) {
    731   HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), false);
    732   if (cache_entry == NULL) return HeapEntry::kNoEntry;
    733   return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value));
    734 }
    735 
    736 
    737 void HeapEntriesMap::Pair(HeapThing thing, int entry) {
    738   HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), true);
    739   ASSERT(cache_entry->value == NULL);
    740   cache_entry->value = reinterpret_cast<void*>(static_cast<intptr_t>(entry));
    741 }
    742 
    743 
    744 HeapObjectsSet::HeapObjectsSet()
    745     : entries_(HeapEntriesMap::HeapThingsMatch) {
    746 }
    747 
    748 
    749 void HeapObjectsSet::Clear() {
    750   entries_.Clear();
    751 }
    752 
    753 
    754 bool HeapObjectsSet::Contains(Object* obj) {
    755   if (!obj->IsHeapObject()) return false;
    756   HeapObject* object = HeapObject::cast(obj);
    757   return entries_.Lookup(object, HeapEntriesMap::Hash(object), false) != NULL;
    758 }
    759 
    760 
    761 void HeapObjectsSet::Insert(Object* obj) {
    762   if (!obj->IsHeapObject()) return;
    763   HeapObject* object = HeapObject::cast(obj);
    764   entries_.Lookup(object, HeapEntriesMap::Hash(object), true);
    765 }
    766 
    767 
    768 const char* HeapObjectsSet::GetTag(Object* obj) {
    769   HeapObject* object = HeapObject::cast(obj);
    770   HashMap::Entry* cache_entry =
    771       entries_.Lookup(object, HeapEntriesMap::Hash(object), false);
    772   return cache_entry != NULL
    773       ? reinterpret_cast<const char*>(cache_entry->value)
    774       : NULL;
    775 }
    776 
    777 
    778 void HeapObjectsSet::SetTag(Object* obj, const char* tag) {
    779   if (!obj->IsHeapObject()) return;
    780   HeapObject* object = HeapObject::cast(obj);
    781   HashMap::Entry* cache_entry =
    782       entries_.Lookup(object, HeapEntriesMap::Hash(object), true);
    783   cache_entry->value = const_cast<char*>(tag);
    784 }
    785 
    786 
    787 HeapObject* const V8HeapExplorer::kInternalRootObject =
    788     reinterpret_cast<HeapObject*>(
    789         static_cast<intptr_t>(HeapObjectsMap::kInternalRootObjectId));
    790 HeapObject* const V8HeapExplorer::kGcRootsObject =
    791     reinterpret_cast<HeapObject*>(
    792         static_cast<intptr_t>(HeapObjectsMap::kGcRootsObjectId));
    793 HeapObject* const V8HeapExplorer::kFirstGcSubrootObject =
    794     reinterpret_cast<HeapObject*>(
    795         static_cast<intptr_t>(HeapObjectsMap::kGcRootsFirstSubrootId));
    796 HeapObject* const V8HeapExplorer::kLastGcSubrootObject =
    797     reinterpret_cast<HeapObject*>(
    798         static_cast<intptr_t>(HeapObjectsMap::kFirstAvailableObjectId));
    799 
    800 
    801 V8HeapExplorer::V8HeapExplorer(
    802     HeapSnapshot* snapshot,
    803     SnapshottingProgressReportingInterface* progress,
    804     v8::HeapProfiler::ObjectNameResolver* resolver)
    805     : heap_(snapshot->profiler()->heap_object_map()->heap()),
    806       snapshot_(snapshot),
    807       names_(snapshot_->profiler()->names()),
    808       heap_object_map_(snapshot_->profiler()->heap_object_map()),
    809       progress_(progress),
    810       filler_(NULL),
    811       global_object_name_resolver_(resolver) {
    812 }
    813 
    814 
    815 V8HeapExplorer::~V8HeapExplorer() {
    816 }
    817 
    818 
    819 HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) {
    820   return AddEntry(reinterpret_cast<HeapObject*>(ptr));
    821 }
    822 
    823 
    824 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) {
    825   if (object == kInternalRootObject) {
    826     snapshot_->AddRootEntry();
    827     return snapshot_->root();
    828   } else if (object == kGcRootsObject) {
    829     HeapEntry* entry = snapshot_->AddGcRootsEntry();
    830     return entry;
    831   } else if (object >= kFirstGcSubrootObject && object < kLastGcSubrootObject) {
    832     HeapEntry* entry = snapshot_->AddGcSubrootEntry(GetGcSubrootOrder(object));
    833     return entry;
    834   } else if (object->IsJSFunction()) {
    835     JSFunction* func = JSFunction::cast(object);
    836     SharedFunctionInfo* shared = func->shared();
    837     const char* name = shared->bound() ? "native_bind" :
    838         names_->GetName(String::cast(shared->name()));
    839     return AddEntry(object, HeapEntry::kClosure, name);
    840   } else if (object->IsJSRegExp()) {
    841     JSRegExp* re = JSRegExp::cast(object);
    842     return AddEntry(object,
    843                     HeapEntry::kRegExp,
    844                     names_->GetName(re->Pattern()));
    845   } else if (object->IsJSObject()) {
    846     const char* name = names_->GetName(
    847         GetConstructorName(JSObject::cast(object)));
    848     if (object->IsJSGlobalObject()) {
    849       const char* tag = objects_tags_.GetTag(object);
    850       if (tag != NULL) {
    851         name = names_->GetFormatted("%s / %s", name, tag);
    852       }
    853     }
    854     return AddEntry(object, HeapEntry::kObject, name);
    855   } else if (object->IsString()) {
    856     String* string = String::cast(object);
    857     if (string->IsConsString())
    858       return AddEntry(object,
    859                       HeapEntry::kConsString,
    860                       "(concatenated string)");
    861     if (string->IsSlicedString())
    862       return AddEntry(object,
    863                       HeapEntry::kSlicedString,
    864                       "(sliced string)");
    865     return AddEntry(object,
    866                     HeapEntry::kString,
    867                     names_->GetName(String::cast(object)));
    868   } else if (object->IsCode()) {
    869     return AddEntry(object, HeapEntry::kCode, "");
    870   } else if (object->IsSharedFunctionInfo()) {
    871     String* name = String::cast(SharedFunctionInfo::cast(object)->name());
    872     return AddEntry(object,
    873                     HeapEntry::kCode,
    874                     names_->GetName(name));
    875   } else if (object->IsScript()) {
    876     Object* name = Script::cast(object)->name();
    877     return AddEntry(object,
    878                     HeapEntry::kCode,
    879                     name->IsString()
    880                         ? names_->GetName(String::cast(name))
    881                         : "");
    882   } else if (object->IsNativeContext()) {
    883     return AddEntry(object, HeapEntry::kHidden, "system / NativeContext");
    884   } else if (object->IsContext()) {
    885     return AddEntry(object, HeapEntry::kObject, "system / Context");
    886   } else if (object->IsFixedArray() ||
    887              object->IsFixedDoubleArray() ||
    888              object->IsByteArray() ||
    889              object->IsExternalArray()) {
    890     return AddEntry(object, HeapEntry::kArray, "");
    891   } else if (object->IsHeapNumber()) {
    892     return AddEntry(object, HeapEntry::kHeapNumber, "number");
    893   }
    894   return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object));
    895 }
    896 
    897 
    898 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
    899                                     HeapEntry::Type type,
    900                                     const char* name) {
    901   int object_size = object->Size();
    902   SnapshotObjectId object_id =
    903       heap_object_map_->FindOrAddEntry(object->address(), object_size);
    904   return snapshot_->AddEntry(type, name, object_id, object_size);
    905 }
    906 
    907 
    908 class GcSubrootsEnumerator : public ObjectVisitor {
    909  public:
    910   GcSubrootsEnumerator(
    911       SnapshotFillerInterface* filler, V8HeapExplorer* explorer)
    912       : filler_(filler),
    913         explorer_(explorer),
    914         previous_object_count_(0),
    915         object_count_(0) {
    916   }
    917   void VisitPointers(Object** start, Object** end) {
    918     object_count_ += end - start;
    919   }
    920   void Synchronize(VisitorSynchronization::SyncTag tag) {
    921     // Skip empty subroots.
    922     if (previous_object_count_ != object_count_) {
    923       previous_object_count_ = object_count_;
    924       filler_->AddEntry(V8HeapExplorer::GetNthGcSubrootObject(tag), explorer_);
    925     }
    926   }
    927  private:
    928   SnapshotFillerInterface* filler_;
    929   V8HeapExplorer* explorer_;
    930   intptr_t previous_object_count_;
    931   intptr_t object_count_;
    932 };
    933 
    934 
    935 void V8HeapExplorer::AddRootEntries(SnapshotFillerInterface* filler) {
    936   filler->AddEntry(kInternalRootObject, this);
    937   filler->AddEntry(kGcRootsObject, this);
    938   GcSubrootsEnumerator enumerator(filler, this);
    939   heap_->IterateRoots(&enumerator, VISIT_ALL);
    940 }
    941 
    942 
    943 const char* V8HeapExplorer::GetSystemEntryName(HeapObject* object) {
    944   switch (object->map()->instance_type()) {
    945     case MAP_TYPE:
    946       switch (Map::cast(object)->instance_type()) {
    947 #define MAKE_STRING_MAP_CASE(instance_type, size, name, Name) \
    948         case instance_type: return "system / Map (" #Name ")";
    949       STRING_TYPE_LIST(MAKE_STRING_MAP_CASE)
    950 #undef MAKE_STRING_MAP_CASE
    951         default: return "system / Map";
    952       }
    953     case CELL_TYPE: return "system / Cell";
    954     case PROPERTY_CELL_TYPE: return "system / PropertyCell";
    955     case FOREIGN_TYPE: return "system / Foreign";
    956     case ODDBALL_TYPE: return "system / Oddball";
    957 #define MAKE_STRUCT_CASE(NAME, Name, name) \
    958     case NAME##_TYPE: return "system / "#Name;
    959   STRUCT_LIST(MAKE_STRUCT_CASE)
    960 #undef MAKE_STRUCT_CASE
    961     default: return "system";
    962   }
    963 }
    964 
    965 
    966 int V8HeapExplorer::EstimateObjectsCount(HeapIterator* iterator) {
    967   int objects_count = 0;
    968   for (HeapObject* obj = iterator->next();
    969        obj != NULL;
    970        obj = iterator->next()) {
    971     objects_count++;
    972   }
    973   return objects_count;
    974 }
    975 
    976 
    977 class IndexedReferencesExtractor : public ObjectVisitor {
    978  public:
    979   IndexedReferencesExtractor(V8HeapExplorer* generator,
    980                              HeapObject* parent_obj,
    981                              int parent)
    982       : generator_(generator),
    983         parent_obj_(parent_obj),
    984         parent_(parent),
    985         next_index_(0) {
    986   }
    987   void VisitCodeEntry(Address entry_address) {
    988      Code* code = Code::cast(Code::GetObjectFromEntryAddress(entry_address));
    989      generator_->SetInternalReference(parent_obj_, parent_, "code", code);
    990      generator_->TagCodeObject(code);
    991   }
    992   void VisitPointers(Object** start, Object** end) {
    993     for (Object** p = start; p < end; p++) {
    994       if (CheckVisitedAndUnmark(p)) continue;
    995       generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p);
    996     }
    997   }
    998   static void MarkVisitedField(HeapObject* obj, int offset) {
    999     if (offset < 0) return;
   1000     Address field = obj->address() + offset;
   1001     ASSERT(!Memory::Object_at(field)->IsFailure());
   1002     ASSERT(Memory::Object_at(field)->IsHeapObject());
   1003     *field |= kFailureTag;
   1004   }
   1005 
   1006  private:
   1007   bool CheckVisitedAndUnmark(Object** field) {
   1008     if ((*field)->IsFailure()) {
   1009       intptr_t untagged = reinterpret_cast<intptr_t>(*field) & ~kFailureTagMask;
   1010       *field = reinterpret_cast<Object*>(untagged | kHeapObjectTag);
   1011       ASSERT((*field)->IsHeapObject());
   1012       return true;
   1013     }
   1014     return false;
   1015   }
   1016   V8HeapExplorer* generator_;
   1017   HeapObject* parent_obj_;
   1018   int parent_;
   1019   int next_index_;
   1020 };
   1021 
   1022 
   1023 void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
   1024   HeapEntry* heap_entry = GetEntry(obj);
   1025   if (heap_entry == NULL) return;  // No interest in this object.
   1026   int entry = heap_entry->index();
   1027 
   1028   if (obj->IsJSGlobalProxy()) {
   1029     ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
   1030   } else if (obj->IsJSObject()) {
   1031     ExtractJSObjectReferences(entry, JSObject::cast(obj));
   1032   } else if (obj->IsString()) {
   1033     ExtractStringReferences(entry, String::cast(obj));
   1034   } else if (obj->IsContext()) {
   1035     ExtractContextReferences(entry, Context::cast(obj));
   1036   } else if (obj->IsMap()) {
   1037     ExtractMapReferences(entry, Map::cast(obj));
   1038   } else if (obj->IsSharedFunctionInfo()) {
   1039     ExtractSharedFunctionInfoReferences(entry, SharedFunctionInfo::cast(obj));
   1040   } else if (obj->IsScript()) {
   1041     ExtractScriptReferences(entry, Script::cast(obj));
   1042   } else if (obj->IsAccessorPair()) {
   1043     ExtractAccessorPairReferences(entry, AccessorPair::cast(obj));
   1044   } else if (obj->IsCodeCache()) {
   1045     ExtractCodeCacheReferences(entry, CodeCache::cast(obj));
   1046   } else if (obj->IsCode()) {
   1047     ExtractCodeReferences(entry, Code::cast(obj));
   1048   } else if (obj->IsCell()) {
   1049     ExtractCellReferences(entry, Cell::cast(obj));
   1050   } else if (obj->IsPropertyCell()) {
   1051     ExtractPropertyCellReferences(entry, PropertyCell::cast(obj));
   1052   } else if (obj->IsAllocationSite()) {
   1053     ExtractAllocationSiteReferences(entry, AllocationSite::cast(obj));
   1054   }
   1055   SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
   1056 
   1057   // Extract unvisited fields as hidden references and restore tags
   1058   // of visited fields.
   1059   IndexedReferencesExtractor refs_extractor(this, obj, entry);
   1060   obj->Iterate(&refs_extractor);
   1061 }
   1062 
   1063 
   1064 void V8HeapExplorer::ExtractJSGlobalProxyReferences(
   1065     int entry, JSGlobalProxy* proxy) {
   1066   SetInternalReference(proxy, entry,
   1067                        "native_context", proxy->native_context(),
   1068                        JSGlobalProxy::kNativeContextOffset);
   1069 }
   1070 
   1071 
   1072 void V8HeapExplorer::ExtractJSObjectReferences(
   1073     int entry, JSObject* js_obj) {
   1074   HeapObject* obj = js_obj;
   1075   ExtractClosureReferences(js_obj, entry);
   1076   ExtractPropertyReferences(js_obj, entry);
   1077   ExtractElementReferences(js_obj, entry);
   1078   ExtractInternalReferences(js_obj, entry);
   1079   SetPropertyReference(
   1080       obj, entry, heap_->proto_string(), js_obj->GetPrototype());
   1081   if (obj->IsJSFunction()) {
   1082     JSFunction* js_fun = JSFunction::cast(js_obj);
   1083     Object* proto_or_map = js_fun->prototype_or_initial_map();
   1084     if (!proto_or_map->IsTheHole()) {
   1085       if (!proto_or_map->IsMap()) {
   1086         SetPropertyReference(
   1087             obj, entry,
   1088             heap_->prototype_string(), proto_or_map,
   1089             NULL,
   1090             JSFunction::kPrototypeOrInitialMapOffset);
   1091       } else {
   1092         SetPropertyReference(
   1093             obj, entry,
   1094             heap_->prototype_string(), js_fun->prototype());
   1095         SetInternalReference(
   1096             obj, entry, "initial_map", proto_or_map,
   1097             JSFunction::kPrototypeOrInitialMapOffset);
   1098       }
   1099     }
   1100     SharedFunctionInfo* shared_info = js_fun->shared();
   1101     // JSFunction has either bindings or literals and never both.
   1102     bool bound = shared_info->bound();
   1103     TagObject(js_fun->literals_or_bindings(),
   1104               bound ? "(function bindings)" : "(function literals)");
   1105     SetInternalReference(js_fun, entry,
   1106                          bound ? "bindings" : "literals",
   1107                          js_fun->literals_or_bindings(),
   1108                          JSFunction::kLiteralsOffset);
   1109     TagObject(shared_info, "(shared function info)");
   1110     SetInternalReference(js_fun, entry,
   1111                          "shared", shared_info,
   1112                          JSFunction::kSharedFunctionInfoOffset);
   1113     TagObject(js_fun->context(), "(context)");
   1114     SetInternalReference(js_fun, entry,
   1115                          "context", js_fun->context(),
   1116                          JSFunction::kContextOffset);
   1117     for (int i = JSFunction::kNonWeakFieldsEndOffset;
   1118          i < JSFunction::kSize;
   1119          i += kPointerSize) {
   1120       SetWeakReference(js_fun, entry, i, *HeapObject::RawField(js_fun, i), i);
   1121     }
   1122   } else if (obj->IsGlobalObject()) {
   1123     GlobalObject* global_obj = GlobalObject::cast(obj);
   1124     SetInternalReference(global_obj, entry,
   1125                          "builtins", global_obj->builtins(),
   1126                          GlobalObject::kBuiltinsOffset);
   1127     SetInternalReference(global_obj, entry,
   1128                          "native_context", global_obj->native_context(),
   1129                          GlobalObject::kNativeContextOffset);
   1130     SetInternalReference(global_obj, entry,
   1131                          "global_receiver", global_obj->global_receiver(),
   1132                          GlobalObject::kGlobalReceiverOffset);
   1133   }
   1134   TagObject(js_obj->properties(), "(object properties)");
   1135   SetInternalReference(obj, entry,
   1136                        "properties", js_obj->properties(),
   1137                        JSObject::kPropertiesOffset);
   1138   TagObject(js_obj->elements(), "(object elements)");
   1139   SetInternalReference(obj, entry,
   1140                        "elements", js_obj->elements(),
   1141                        JSObject::kElementsOffset);
   1142 }
   1143 
   1144 
   1145 void V8HeapExplorer::ExtractStringReferences(int entry, String* string) {
   1146   if (string->IsConsString()) {
   1147     ConsString* cs = ConsString::cast(string);
   1148     SetInternalReference(cs, entry, "first", cs->first(),
   1149                          ConsString::kFirstOffset);
   1150     SetInternalReference(cs, entry, "second", cs->second(),
   1151                          ConsString::kSecondOffset);
   1152   } else if (string->IsSlicedString()) {
   1153     SlicedString* ss = SlicedString::cast(string);
   1154     SetInternalReference(ss, entry, "parent", ss->parent(),
   1155                          SlicedString::kParentOffset);
   1156   }
   1157 }
   1158 
   1159 
   1160 void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
   1161   if (context == context->declaration_context()) {
   1162     ScopeInfo* scope_info = context->closure()->shared()->scope_info();
   1163     // Add context allocated locals.
   1164     int context_locals = scope_info->ContextLocalCount();
   1165     for (int i = 0; i < context_locals; ++i) {
   1166       String* local_name = scope_info->ContextLocalName(i);
   1167       int idx = Context::MIN_CONTEXT_SLOTS + i;
   1168       SetContextReference(context, entry, local_name, context->get(idx),
   1169                           Context::OffsetOfElementAt(idx));
   1170     }
   1171     if (scope_info->HasFunctionName()) {
   1172       String* name = scope_info->FunctionName();
   1173       VariableMode mode;
   1174       int idx = scope_info->FunctionContextSlotIndex(name, &mode);
   1175       if (idx >= 0) {
   1176         SetContextReference(context, entry, name, context->get(idx),
   1177                             Context::OffsetOfElementAt(idx));
   1178       }
   1179     }
   1180   }
   1181 
   1182 #define EXTRACT_CONTEXT_FIELD(index, type, name) \
   1183   SetInternalReference(context, entry, #name, context->get(Context::index), \
   1184       FixedArray::OffsetOfElementAt(Context::index));
   1185   EXTRACT_CONTEXT_FIELD(CLOSURE_INDEX, JSFunction, closure);
   1186   EXTRACT_CONTEXT_FIELD(PREVIOUS_INDEX, Context, previous);
   1187   EXTRACT_CONTEXT_FIELD(EXTENSION_INDEX, Object, extension);
   1188   EXTRACT_CONTEXT_FIELD(GLOBAL_OBJECT_INDEX, GlobalObject, global);
   1189   if (context->IsNativeContext()) {
   1190     TagObject(context->jsfunction_result_caches(),
   1191               "(context func. result caches)");
   1192     TagObject(context->normalized_map_cache(), "(context norm. map cache)");
   1193     TagObject(context->runtime_context(), "(runtime context)");
   1194     TagObject(context->embedder_data(), "(context data)");
   1195     NATIVE_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD);
   1196 #undef EXTRACT_CONTEXT_FIELD
   1197     for (int i = Context::FIRST_WEAK_SLOT;
   1198          i < Context::NATIVE_CONTEXT_SLOTS;
   1199          ++i) {
   1200       SetWeakReference(context, entry, i, context->get(i),
   1201           FixedArray::OffsetOfElementAt(i));
   1202     }
   1203   }
   1204 }
   1205 
   1206 
   1207 void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
   1208   if (map->HasTransitionArray()) {
   1209     TransitionArray* transitions = map->transitions();
   1210     int transitions_entry = GetEntry(transitions)->index();
   1211     Object* back_pointer = transitions->back_pointer_storage();
   1212     TagObject(back_pointer, "(back pointer)");
   1213     SetInternalReference(transitions, transitions_entry,
   1214                          "back_pointer", back_pointer);
   1215     TagObject(transitions, "(transition array)");
   1216     SetInternalReference(map, entry,
   1217                          "transitions", transitions,
   1218                          Map::kTransitionsOrBackPointerOffset);
   1219   } else {
   1220     Object* back_pointer = map->GetBackPointer();
   1221     TagObject(back_pointer, "(back pointer)");
   1222     SetInternalReference(map, entry,
   1223                          "back_pointer", back_pointer,
   1224                          Map::kTransitionsOrBackPointerOffset);
   1225   }
   1226   DescriptorArray* descriptors = map->instance_descriptors();
   1227   TagObject(descriptors, "(map descriptors)");
   1228   SetInternalReference(map, entry,
   1229                        "descriptors", descriptors,
   1230                        Map::kDescriptorsOffset);
   1231 
   1232   SetInternalReference(map, entry,
   1233                        "code_cache", map->code_cache(),
   1234                        Map::kCodeCacheOffset);
   1235   SetInternalReference(map, entry,
   1236                        "prototype", map->prototype(), Map::kPrototypeOffset);
   1237   SetInternalReference(map, entry,
   1238                        "constructor", map->constructor(),
   1239                        Map::kConstructorOffset);
   1240   TagObject(map->dependent_code(), "(dependent code)");
   1241   SetInternalReference(map, entry,
   1242                        "dependent_code", map->dependent_code(),
   1243                        Map::kDependentCodeOffset);
   1244 }
   1245 
   1246 
   1247 void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
   1248     int entry, SharedFunctionInfo* shared) {
   1249   HeapObject* obj = shared;
   1250   String* shared_name = shared->DebugName();
   1251   const char* name = NULL;
   1252   if (shared_name != *heap_->isolate()->factory()->empty_string()) {
   1253     name = names_->GetName(shared_name);
   1254     TagObject(shared->code(), names_->GetFormatted("(code for %s)", name));
   1255   } else {
   1256     TagObject(shared->code(), names_->GetFormatted("(%s code)",
   1257         Code::Kind2String(shared->code()->kind())));
   1258   }
   1259 
   1260   SetInternalReference(obj, entry,
   1261                        "name", shared->name(),
   1262                        SharedFunctionInfo::kNameOffset);
   1263   SetInternalReference(obj, entry,
   1264                        "code", shared->code(),
   1265                        SharedFunctionInfo::kCodeOffset);
   1266   TagObject(shared->scope_info(), "(function scope info)");
   1267   SetInternalReference(obj, entry,
   1268                        "scope_info", shared->scope_info(),
   1269                        SharedFunctionInfo::kScopeInfoOffset);
   1270   SetInternalReference(obj, entry,
   1271                        "instance_class_name", shared->instance_class_name(),
   1272                        SharedFunctionInfo::kInstanceClassNameOffset);
   1273   SetInternalReference(obj, entry,
   1274                        "script", shared->script(),
   1275                        SharedFunctionInfo::kScriptOffset);
   1276   const char* construct_stub_name = name ?
   1277       names_->GetFormatted("(construct stub code for %s)", name) :
   1278       "(construct stub code)";
   1279   TagObject(shared->construct_stub(), construct_stub_name);
   1280   SetInternalReference(obj, entry,
   1281                        "construct_stub", shared->construct_stub(),
   1282                        SharedFunctionInfo::kConstructStubOffset);
   1283   SetInternalReference(obj, entry,
   1284                        "function_data", shared->function_data(),
   1285                        SharedFunctionInfo::kFunctionDataOffset);
   1286   SetInternalReference(obj, entry,
   1287                        "debug_info", shared->debug_info(),
   1288                        SharedFunctionInfo::kDebugInfoOffset);
   1289   SetInternalReference(obj, entry,
   1290                        "inferred_name", shared->inferred_name(),
   1291                        SharedFunctionInfo::kInferredNameOffset);
   1292   SetInternalReference(obj, entry,
   1293                        "optimized_code_map", shared->optimized_code_map(),
   1294                        SharedFunctionInfo::kOptimizedCodeMapOffset);
   1295   SetWeakReference(obj, entry,
   1296                    1, shared->initial_map(),
   1297                    SharedFunctionInfo::kInitialMapOffset);
   1298 }
   1299 
   1300 
   1301 void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) {
   1302   HeapObject* obj = script;
   1303   SetInternalReference(obj, entry,
   1304                        "source", script->source(),
   1305                        Script::kSourceOffset);
   1306   SetInternalReference(obj, entry,
   1307                        "name", script->name(),
   1308                        Script::kNameOffset);
   1309   SetInternalReference(obj, entry,
   1310                        "data", script->data(),
   1311                        Script::kDataOffset);
   1312   SetInternalReference(obj, entry,
   1313                        "context_data", script->context_data(),
   1314                        Script::kContextOffset);
   1315   TagObject(script->line_ends(), "(script line ends)");
   1316   SetInternalReference(obj, entry,
   1317                        "line_ends", script->line_ends(),
   1318                        Script::kLineEndsOffset);
   1319 }
   1320 
   1321 
   1322 void V8HeapExplorer::ExtractAccessorPairReferences(
   1323     int entry, AccessorPair* accessors) {
   1324   SetInternalReference(accessors, entry, "getter", accessors->getter(),
   1325                        AccessorPair::kGetterOffset);
   1326   SetInternalReference(accessors, entry, "setter", accessors->setter(),
   1327                        AccessorPair::kSetterOffset);
   1328 }
   1329 
   1330 
   1331 void V8HeapExplorer::ExtractCodeCacheReferences(
   1332     int entry, CodeCache* code_cache) {
   1333   TagObject(code_cache->default_cache(), "(default code cache)");
   1334   SetInternalReference(code_cache, entry,
   1335                        "default_cache", code_cache->default_cache(),
   1336                        CodeCache::kDefaultCacheOffset);
   1337   TagObject(code_cache->normal_type_cache(), "(code type cache)");
   1338   SetInternalReference(code_cache, entry,
   1339                        "type_cache", code_cache->normal_type_cache(),
   1340                        CodeCache::kNormalTypeCacheOffset);
   1341 }
   1342 
   1343 
   1344 void V8HeapExplorer::TagCodeObject(Code* code, const char* external_name) {
   1345   TagObject(code, names_->GetFormatted("(%s code)", external_name));
   1346 }
   1347 
   1348 
   1349 void V8HeapExplorer::TagCodeObject(Code* code) {
   1350   if (code->kind() == Code::STUB) {
   1351     TagObject(code, names_->GetFormatted(
   1352         "(%s code)", CodeStub::MajorName(
   1353             static_cast<CodeStub::Major>(code->major_key()), true)));
   1354   }
   1355 }
   1356 
   1357 
   1358 void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) {
   1359   TagCodeObject(code);
   1360   TagObject(code->relocation_info(), "(code relocation info)");
   1361   SetInternalReference(code, entry,
   1362                        "relocation_info", code->relocation_info(),
   1363                        Code::kRelocationInfoOffset);
   1364   SetInternalReference(code, entry,
   1365                        "handler_table", code->handler_table(),
   1366                        Code::kHandlerTableOffset);
   1367   TagObject(code->deoptimization_data(), "(code deopt data)");
   1368   SetInternalReference(code, entry,
   1369                        "deoptimization_data", code->deoptimization_data(),
   1370                        Code::kDeoptimizationDataOffset);
   1371   if (code->kind() == Code::FUNCTION) {
   1372     SetInternalReference(code, entry,
   1373                          "type_feedback_info", code->type_feedback_info(),
   1374                          Code::kTypeFeedbackInfoOffset);
   1375   }
   1376   SetInternalReference(code, entry,
   1377                        "gc_metadata", code->gc_metadata(),
   1378                        Code::kGCMetadataOffset);
   1379 }
   1380 
   1381 
   1382 void V8HeapExplorer::ExtractCellReferences(int entry, Cell* cell) {
   1383   SetInternalReference(cell, entry, "value", cell->value(), Cell::kValueOffset);
   1384 }
   1385 
   1386 
   1387 void V8HeapExplorer::ExtractPropertyCellReferences(int entry,
   1388                                                    PropertyCell* cell) {
   1389   ExtractCellReferences(entry, cell);
   1390   SetInternalReference(cell, entry, "type", cell->type(),
   1391                        PropertyCell::kTypeOffset);
   1392   SetInternalReference(cell, entry, "dependent_code", cell->dependent_code(),
   1393                        PropertyCell::kDependentCodeOffset);
   1394 }
   1395 
   1396 
   1397 void V8HeapExplorer::ExtractAllocationSiteReferences(int entry,
   1398                                                      AllocationSite* site) {
   1399   SetInternalReference(site, entry, "transition_info", site->transition_info(),
   1400                        AllocationSite::kTransitionInfoOffset);
   1401   SetInternalReference(site, entry, "nested_site", site->nested_site(),
   1402                        AllocationSite::kNestedSiteOffset);
   1403   SetInternalReference(site, entry, "memento_found_count",
   1404                        site->memento_found_count(),
   1405                        AllocationSite::kMementoFoundCountOffset);
   1406   SetInternalReference(site, entry, "memento_create_count",
   1407                        site->memento_create_count(),
   1408                        AllocationSite::kMementoCreateCountOffset);
   1409   SetInternalReference(site, entry, "pretenure_decision",
   1410                        site->pretenure_decision(),
   1411                        AllocationSite::kPretenureDecisionOffset);
   1412   SetInternalReference(site, entry, "dependent_code", site->dependent_code(),
   1413                        AllocationSite::kDependentCodeOffset);
   1414 }
   1415 
   1416 
   1417 void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) {
   1418   if (!js_obj->IsJSFunction()) return;
   1419 
   1420   JSFunction* func = JSFunction::cast(js_obj);
   1421   if (func->shared()->bound()) {
   1422     FixedArray* bindings = func->function_bindings();
   1423     SetNativeBindReference(js_obj, entry, "bound_this",
   1424                            bindings->get(JSFunction::kBoundThisIndex));
   1425     SetNativeBindReference(js_obj, entry, "bound_function",
   1426                            bindings->get(JSFunction::kBoundFunctionIndex));
   1427     for (int i = JSFunction::kBoundArgumentsStartIndex;
   1428          i < bindings->length(); i++) {
   1429       const char* reference_name = names_->GetFormatted(
   1430           "bound_argument_%d",
   1431           i - JSFunction::kBoundArgumentsStartIndex);
   1432       SetNativeBindReference(js_obj, entry, reference_name,
   1433                              bindings->get(i));
   1434     }
   1435   }
   1436 }
   1437 
   1438 
   1439 void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
   1440   if (js_obj->HasFastProperties()) {
   1441     DescriptorArray* descs = js_obj->map()->instance_descriptors();
   1442     int real_size = js_obj->map()->NumberOfOwnDescriptors();
   1443     for (int i = 0; i < real_size; i++) {
   1444       switch (descs->GetType(i)) {
   1445         case FIELD: {
   1446           int index = descs->GetFieldIndex(i);
   1447 
   1448           Name* k = descs->GetKey(i);
   1449           if (index < js_obj->map()->inobject_properties()) {
   1450             Object* value = js_obj->InObjectPropertyAt(index);
   1451             if (k != heap_->hidden_string()) {
   1452               SetPropertyReference(
   1453                   js_obj, entry,
   1454                   k, value,
   1455                   NULL,
   1456                   js_obj->GetInObjectPropertyOffset(index));
   1457             } else {
   1458               TagObject(value, "(hidden properties)");
   1459               SetInternalReference(
   1460                   js_obj, entry,
   1461                   "hidden_properties", value,
   1462                   js_obj->GetInObjectPropertyOffset(index));
   1463             }
   1464           } else {
   1465             Object* value = js_obj->RawFastPropertyAt(index);
   1466             if (k != heap_->hidden_string()) {
   1467               SetPropertyReference(js_obj, entry, k, value);
   1468             } else {
   1469               TagObject(value, "(hidden properties)");
   1470               SetInternalReference(js_obj, entry, "hidden_properties", value);
   1471             }
   1472           }
   1473           break;
   1474         }
   1475         case CONSTANT:
   1476           SetPropertyReference(
   1477               js_obj, entry,
   1478               descs->GetKey(i), descs->GetConstant(i));
   1479           break;
   1480         case CALLBACKS:
   1481           ExtractAccessorPairProperty(
   1482               js_obj, entry,
   1483               descs->GetKey(i), descs->GetValue(i));
   1484           break;
   1485         case NORMAL:  // only in slow mode
   1486         case HANDLER:  // only in lookup results, not in descriptors
   1487         case INTERCEPTOR:  // only in lookup results, not in descriptors
   1488           break;
   1489         case TRANSITION:
   1490         case NONEXISTENT:
   1491           UNREACHABLE();
   1492           break;
   1493       }
   1494     }
   1495   } else {
   1496     NameDictionary* dictionary = js_obj->property_dictionary();
   1497     int length = dictionary->Capacity();
   1498     for (int i = 0; i < length; ++i) {
   1499       Object* k = dictionary->KeyAt(i);
   1500       if (dictionary->IsKey(k)) {
   1501         Object* target = dictionary->ValueAt(i);
   1502         // We assume that global objects can only have slow properties.
   1503         Object* value = target->IsPropertyCell()
   1504             ? PropertyCell::cast(target)->value()
   1505             : target;
   1506         if (k == heap_->hidden_string()) {
   1507           TagObject(value, "(hidden properties)");
   1508           SetInternalReference(js_obj, entry, "hidden_properties", value);
   1509           continue;
   1510         }
   1511         if (ExtractAccessorPairProperty(js_obj, entry, k, value)) continue;
   1512         SetPropertyReference(js_obj, entry, String::cast(k), value);
   1513       }
   1514     }
   1515   }
   1516 }
   1517 
   1518 
   1519 bool V8HeapExplorer::ExtractAccessorPairProperty(
   1520     JSObject* js_obj, int entry, Object* key, Object* callback_obj) {
   1521   if (!callback_obj->IsAccessorPair()) return false;
   1522   AccessorPair* accessors = AccessorPair::cast(callback_obj);
   1523   Object* getter = accessors->getter();
   1524   if (!getter->IsOddball()) {
   1525     SetPropertyReference(js_obj, entry, String::cast(key), getter, "get %s");
   1526   }
   1527   Object* setter = accessors->setter();
   1528   if (!setter->IsOddball()) {
   1529     SetPropertyReference(js_obj, entry, String::cast(key), setter, "set %s");
   1530   }
   1531   return true;
   1532 }
   1533 
   1534 
   1535 void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) {
   1536   if (js_obj->HasFastObjectElements()) {
   1537     FixedArray* elements = FixedArray::cast(js_obj->elements());
   1538     int length = js_obj->IsJSArray() ?
   1539         Smi::cast(JSArray::cast(js_obj)->length())->value() :
   1540         elements->length();
   1541     for (int i = 0; i < length; ++i) {
   1542       if (!elements->get(i)->IsTheHole()) {
   1543         SetElementReference(js_obj, entry, i, elements->get(i));
   1544       }
   1545     }
   1546   } else if (js_obj->HasDictionaryElements()) {
   1547     SeededNumberDictionary* dictionary = js_obj->element_dictionary();
   1548     int length = dictionary->Capacity();
   1549     for (int i = 0; i < length; ++i) {
   1550       Object* k = dictionary->KeyAt(i);
   1551       if (dictionary->IsKey(k)) {
   1552         ASSERT(k->IsNumber());
   1553         uint32_t index = static_cast<uint32_t>(k->Number());
   1554         SetElementReference(js_obj, entry, index, dictionary->ValueAt(i));
   1555       }
   1556     }
   1557   }
   1558 }
   1559 
   1560 
   1561 void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, int entry) {
   1562   int length = js_obj->GetInternalFieldCount();
   1563   for (int i = 0; i < length; ++i) {
   1564     Object* o = js_obj->GetInternalField(i);
   1565     SetInternalReference(
   1566         js_obj, entry, i, o, js_obj->GetInternalFieldOffset(i));
   1567   }
   1568 }
   1569 
   1570 
   1571 String* V8HeapExplorer::GetConstructorName(JSObject* object) {
   1572   Heap* heap = object->GetHeap();
   1573   if (object->IsJSFunction()) return heap->closure_string();
   1574   String* constructor_name = object->constructor_name();
   1575   if (constructor_name == heap->Object_string()) {
   1576     // Look up an immediate "constructor" property, if it is a function,
   1577     // return its name. This is for instances of binding objects, which
   1578     // have prototype constructor type "Object".
   1579     Object* constructor_prop = NULL;
   1580     LookupResult result(heap->isolate());
   1581     object->LocalLookupRealNamedProperty(heap->constructor_string(), &result);
   1582     if (!result.IsFound()) return object->constructor_name();
   1583 
   1584     constructor_prop = result.GetLazyValue();
   1585     if (constructor_prop->IsJSFunction()) {
   1586       Object* maybe_name =
   1587           JSFunction::cast(constructor_prop)->shared()->name();
   1588       if (maybe_name->IsString()) {
   1589         String* name = String::cast(maybe_name);
   1590         if (name->length() > 0) return name;
   1591       }
   1592     }
   1593   }
   1594   return object->constructor_name();
   1595 }
   1596 
   1597 
   1598 HeapEntry* V8HeapExplorer::GetEntry(Object* obj) {
   1599   if (!obj->IsHeapObject()) return NULL;
   1600   return filler_->FindOrAddEntry(obj, this);
   1601 }
   1602 
   1603 
   1604 class RootsReferencesExtractor : public ObjectVisitor {
   1605  private:
   1606   struct IndexTag {
   1607     IndexTag(int index, VisitorSynchronization::SyncTag tag)
   1608         : index(index), tag(tag) { }
   1609     int index;
   1610     VisitorSynchronization::SyncTag tag;
   1611   };
   1612 
   1613  public:
   1614   explicit RootsReferencesExtractor(Heap* heap)
   1615       : collecting_all_references_(false),
   1616         previous_reference_count_(0),
   1617         heap_(heap) {
   1618   }
   1619 
   1620   void VisitPointers(Object** start, Object** end) {
   1621     if (collecting_all_references_) {
   1622       for (Object** p = start; p < end; p++) all_references_.Add(*p);
   1623     } else {
   1624       for (Object** p = start; p < end; p++) strong_references_.Add(*p);
   1625     }
   1626   }
   1627 
   1628   void SetCollectingAllReferences() { collecting_all_references_ = true; }
   1629 
   1630   void FillReferences(V8HeapExplorer* explorer) {
   1631     ASSERT(strong_references_.length() <= all_references_.length());
   1632     Builtins* builtins = heap_->isolate()->builtins();
   1633     for (int i = 0; i < reference_tags_.length(); ++i) {
   1634       explorer->SetGcRootsReference(reference_tags_[i].tag);
   1635     }
   1636     int strong_index = 0, all_index = 0, tags_index = 0, builtin_index = 0;
   1637     while (all_index < all_references_.length()) {
   1638       if (strong_index < strong_references_.length() &&
   1639           strong_references_[strong_index] == all_references_[all_index]) {
   1640         explorer->SetGcSubrootReference(reference_tags_[tags_index].tag,
   1641                                         false,
   1642                                         all_references_[all_index]);
   1643         ++strong_index;
   1644       } else {
   1645         explorer->SetGcSubrootReference(reference_tags_[tags_index].tag,
   1646                                         true,
   1647                                         all_references_[all_index]);
   1648       }
   1649       if (reference_tags_[tags_index].tag ==
   1650           VisitorSynchronization::kBuiltins) {
   1651         ASSERT(all_references_[all_index]->IsCode());
   1652         explorer->TagCodeObject(Code::cast(all_references_[all_index]),
   1653             builtins->name(builtin_index++));
   1654       }
   1655       ++all_index;
   1656       if (reference_tags_[tags_index].index == all_index) ++tags_index;
   1657     }
   1658   }
   1659 
   1660   void Synchronize(VisitorSynchronization::SyncTag tag) {
   1661     if (collecting_all_references_ &&
   1662         previous_reference_count_ != all_references_.length()) {
   1663       previous_reference_count_ = all_references_.length();
   1664       reference_tags_.Add(IndexTag(previous_reference_count_, tag));
   1665     }
   1666   }
   1667 
   1668  private:
   1669   bool collecting_all_references_;
   1670   List<Object*> strong_references_;
   1671   List<Object*> all_references_;
   1672   int previous_reference_count_;
   1673   List<IndexTag> reference_tags_;
   1674   Heap* heap_;
   1675 };
   1676 
   1677 
   1678 bool V8HeapExplorer::IterateAndExtractReferences(
   1679     SnapshotFillerInterface* filler) {
   1680   HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable);
   1681 
   1682   filler_ = filler;
   1683   bool interrupted = false;
   1684 
   1685   // Heap iteration with filtering must be finished in any case.
   1686   for (HeapObject* obj = iterator.next();
   1687        obj != NULL;
   1688        obj = iterator.next(), progress_->ProgressStep()) {
   1689     if (!interrupted) {
   1690       ExtractReferences(obj);
   1691       if (!progress_->ProgressReport(false)) interrupted = true;
   1692     }
   1693   }
   1694   if (interrupted) {
   1695     filler_ = NULL;
   1696     return false;
   1697   }
   1698 
   1699   SetRootGcRootsReference();
   1700   RootsReferencesExtractor extractor(heap_);
   1701   heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG);
   1702   extractor.SetCollectingAllReferences();
   1703   heap_->IterateRoots(&extractor, VISIT_ALL);
   1704   extractor.FillReferences(this);
   1705   filler_ = NULL;
   1706   return progress_->ProgressReport(true);
   1707 }
   1708 
   1709 
   1710 bool V8HeapExplorer::IsEssentialObject(Object* object) {
   1711   return object->IsHeapObject()
   1712       && !object->IsOddball()
   1713       && object != heap_->empty_byte_array()
   1714       && object != heap_->empty_fixed_array()
   1715       && object != heap_->empty_descriptor_array()
   1716       && object != heap_->fixed_array_map()
   1717       && object != heap_->cell_map()
   1718       && object != heap_->global_property_cell_map()
   1719       && object != heap_->shared_function_info_map()
   1720       && object != heap_->free_space_map()
   1721       && object != heap_->one_pointer_filler_map()
   1722       && object != heap_->two_pointer_filler_map();
   1723 }
   1724 
   1725 
   1726 void V8HeapExplorer::SetContextReference(HeapObject* parent_obj,
   1727                                          int parent_entry,
   1728                                          String* reference_name,
   1729                                          Object* child_obj,
   1730                                          int field_offset) {
   1731   ASSERT(parent_entry == GetEntry(parent_obj)->index());
   1732   HeapEntry* child_entry = GetEntry(child_obj);
   1733   if (child_entry != NULL) {
   1734     filler_->SetNamedReference(HeapGraphEdge::kContextVariable,
   1735                                parent_entry,
   1736                                names_->GetName(reference_name),
   1737                                child_entry);
   1738     IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
   1739   }
   1740 }
   1741 
   1742 
   1743 void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj,
   1744                                             int parent_entry,
   1745                                             const char* reference_name,
   1746                                             Object* child_obj) {
   1747   ASSERT(parent_entry == GetEntry(parent_obj)->index());
   1748   HeapEntry* child_entry = GetEntry(child_obj);
   1749   if (child_entry != NULL) {
   1750     filler_->SetNamedReference(HeapGraphEdge::kShortcut,
   1751                                parent_entry,
   1752                                reference_name,
   1753                                child_entry);
   1754   }
   1755 }
   1756 
   1757 
   1758 void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
   1759                                          int parent_entry,
   1760                                          int index,
   1761                                          Object* child_obj) {
   1762   ASSERT(parent_entry == GetEntry(parent_obj)->index());
   1763   HeapEntry* child_entry = GetEntry(child_obj);
   1764   if (child_entry != NULL) {
   1765     filler_->SetIndexedReference(HeapGraphEdge::kElement,
   1766                                  parent_entry,
   1767                                  index,
   1768                                  child_entry);
   1769   }
   1770 }
   1771 
   1772 
   1773 void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
   1774                                           int parent_entry,
   1775                                           const char* reference_name,
   1776                                           Object* child_obj,
   1777                                           int field_offset) {
   1778   ASSERT(parent_entry == GetEntry(parent_obj)->index());
   1779   HeapEntry* child_entry = GetEntry(child_obj);
   1780   if (child_entry == NULL) return;
   1781   if (IsEssentialObject(child_obj)) {
   1782     filler_->SetNamedReference(HeapGraphEdge::kInternal,
   1783                                parent_entry,
   1784                                reference_name,
   1785                                child_entry);
   1786   }
   1787   IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
   1788 }
   1789 
   1790 
   1791 void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
   1792                                           int parent_entry,
   1793                                           int index,
   1794                                           Object* child_obj,
   1795                                           int field_offset) {
   1796   ASSERT(parent_entry == GetEntry(parent_obj)->index());
   1797   HeapEntry* child_entry = GetEntry(child_obj);
   1798   if (child_entry == NULL) return;
   1799   if (IsEssentialObject(child_obj)) {
   1800     filler_->SetNamedReference(HeapGraphEdge::kInternal,
   1801                                parent_entry,
   1802                                names_->GetName(index),
   1803                                child_entry);
   1804   }
   1805   IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
   1806 }
   1807 
   1808 
   1809 void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
   1810                                         int parent_entry,
   1811                                         int index,
   1812                                         Object* child_obj) {
   1813   ASSERT(parent_entry == GetEntry(parent_obj)->index());
   1814   HeapEntry* child_entry = GetEntry(child_obj);
   1815   if (child_entry != NULL && IsEssentialObject(child_obj)) {
   1816     filler_->SetIndexedReference(HeapGraphEdge::kHidden,
   1817                                  parent_entry,
   1818                                  index,
   1819                                  child_entry);
   1820   }
   1821 }
   1822 
   1823 
   1824 void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
   1825                                       int parent_entry,
   1826                                       int index,
   1827                                       Object* child_obj,
   1828                                       int field_offset) {
   1829   ASSERT(parent_entry == GetEntry(parent_obj)->index());
   1830   HeapEntry* child_entry = GetEntry(child_obj);
   1831   if (child_entry == NULL) return;
   1832   if (IsEssentialObject(child_obj)) {
   1833     filler_->SetIndexedReference(HeapGraphEdge::kWeak,
   1834                                  parent_entry,
   1835                                  index,
   1836                                  child_entry);
   1837   }
   1838   IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
   1839 }
   1840 
   1841 
   1842 void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
   1843                                           int parent_entry,
   1844                                           Name* reference_name,
   1845                                           Object* child_obj,
   1846                                           const char* name_format_string,
   1847                                           int field_offset) {
   1848   ASSERT(parent_entry == GetEntry(parent_obj)->index());
   1849   HeapEntry* child_entry = GetEntry(child_obj);
   1850   if (child_entry != NULL) {
   1851     HeapGraphEdge::Type type =
   1852         reference_name->IsSymbol() || String::cast(reference_name)->length() > 0
   1853             ? HeapGraphEdge::kProperty : HeapGraphEdge::kInternal;
   1854     const char* name = name_format_string != NULL && reference_name->IsString()
   1855         ? names_->GetFormatted(
   1856               name_format_string,
   1857               *String::cast(reference_name)->ToCString(
   1858                   DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)) :
   1859         names_->GetName(reference_name);
   1860 
   1861     filler_->SetNamedReference(type,
   1862                                parent_entry,
   1863                                name,
   1864                                child_entry);
   1865     IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
   1866   }
   1867 }
   1868 
   1869 
   1870 void V8HeapExplorer::SetRootGcRootsReference() {
   1871   filler_->SetIndexedAutoIndexReference(
   1872       HeapGraphEdge::kElement,
   1873       snapshot_->root()->index(),
   1874       snapshot_->gc_roots());
   1875 }
   1876 
   1877 
   1878 void V8HeapExplorer::SetUserGlobalReference(Object* child_obj) {
   1879   HeapEntry* child_entry = GetEntry(child_obj);
   1880   ASSERT(child_entry != NULL);
   1881   filler_->SetNamedAutoIndexReference(
   1882       HeapGraphEdge::kShortcut,
   1883       snapshot_->root()->index(),
   1884       child_entry);
   1885 }
   1886 
   1887 
   1888 void V8HeapExplorer::SetGcRootsReference(VisitorSynchronization::SyncTag tag) {
   1889   filler_->SetIndexedAutoIndexReference(
   1890       HeapGraphEdge::kElement,
   1891       snapshot_->gc_roots()->index(),
   1892       snapshot_->gc_subroot(tag));
   1893 }
   1894 
   1895 
   1896 void V8HeapExplorer::SetGcSubrootReference(
   1897     VisitorSynchronization::SyncTag tag, bool is_weak, Object* child_obj) {
   1898   HeapEntry* child_entry = GetEntry(child_obj);
   1899   if (child_entry != NULL) {
   1900     const char* name = GetStrongGcSubrootName(child_obj);
   1901     if (name != NULL) {
   1902       filler_->SetNamedReference(
   1903           HeapGraphEdge::kInternal,
   1904           snapshot_->gc_subroot(tag)->index(),
   1905           name,
   1906           child_entry);
   1907     } else {
   1908       filler_->SetIndexedAutoIndexReference(
   1909           is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kElement,
   1910           snapshot_->gc_subroot(tag)->index(),
   1911           child_entry);
   1912     }
   1913 
   1914     // Add a shortcut to JS global object reference at snapshot root.
   1915     if (child_obj->IsNativeContext()) {
   1916       Context* context = Context::cast(child_obj);
   1917       GlobalObject* global = context->global_object();
   1918       if (global->IsJSGlobalObject()) {
   1919         bool is_debug_object = false;
   1920 #ifdef ENABLE_DEBUGGER_SUPPORT
   1921         is_debug_object = heap_->isolate()->debug()->IsDebugGlobal(global);
   1922 #endif
   1923         if (!is_debug_object && !user_roots_.Contains(global)) {
   1924           user_roots_.Insert(global);
   1925           SetUserGlobalReference(global);
   1926         }
   1927       }
   1928     }
   1929   }
   1930 }
   1931 
   1932 
   1933 const char* V8HeapExplorer::GetStrongGcSubrootName(Object* object) {
   1934   if (strong_gc_subroot_names_.is_empty()) {
   1935 #define NAME_ENTRY(name) strong_gc_subroot_names_.SetTag(heap_->name(), #name);
   1936 #define ROOT_NAME(type, name, camel_name) NAME_ENTRY(name)
   1937     STRONG_ROOT_LIST(ROOT_NAME)
   1938 #undef ROOT_NAME
   1939 #define STRUCT_MAP_NAME(NAME, Name, name) NAME_ENTRY(name##_map)
   1940     STRUCT_LIST(STRUCT_MAP_NAME)
   1941 #undef STRUCT_MAP_NAME
   1942 #define STRING_NAME(name, str) NAME_ENTRY(name)
   1943     INTERNALIZED_STRING_LIST(STRING_NAME)
   1944 #undef STRING_NAME
   1945 #undef NAME_ENTRY
   1946     CHECK(!strong_gc_subroot_names_.is_empty());
   1947   }
   1948   return strong_gc_subroot_names_.GetTag(object);
   1949 }
   1950 
   1951 
   1952 void V8HeapExplorer::TagObject(Object* obj, const char* tag) {
   1953   if (IsEssentialObject(obj)) {
   1954     HeapEntry* entry = GetEntry(obj);
   1955     if (entry->name()[0] == '\0') {
   1956       entry->set_name(tag);
   1957     }
   1958   }
   1959 }
   1960 
   1961 
   1962 class GlobalObjectsEnumerator : public ObjectVisitor {
   1963  public:
   1964   virtual void VisitPointers(Object** start, Object** end) {
   1965     for (Object** p = start; p < end; p++) {
   1966       if ((*p)->IsNativeContext()) {
   1967         Context* context = Context::cast(*p);
   1968         JSObject* proxy = context->global_proxy();
   1969         if (proxy->IsJSGlobalProxy()) {
   1970           Object* global = proxy->map()->prototype();
   1971           if (global->IsJSGlobalObject()) {
   1972             objects_.Add(Handle<JSGlobalObject>(JSGlobalObject::cast(global)));
   1973           }
   1974         }
   1975       }
   1976     }
   1977   }
   1978   int count() { return objects_.length(); }
   1979   Handle<JSGlobalObject>& at(int i) { return objects_[i]; }
   1980 
   1981  private:
   1982   List<Handle<JSGlobalObject> > objects_;
   1983 };
   1984 
   1985 
   1986 // Modifies heap. Must not be run during heap traversal.
   1987 void V8HeapExplorer::TagGlobalObjects() {
   1988   Isolate* isolate = heap_->isolate();
   1989   HandleScope scope(isolate);
   1990   GlobalObjectsEnumerator enumerator;
   1991   isolate->global_handles()->IterateAllRoots(&enumerator);
   1992   const char** urls = NewArray<const char*>(enumerator.count());
   1993   for (int i = 0, l = enumerator.count(); i < l; ++i) {
   1994     if (global_object_name_resolver_) {
   1995       HandleScope scope(isolate);
   1996       Handle<JSGlobalObject> global_obj = enumerator.at(i);
   1997       urls[i] = global_object_name_resolver_->GetName(
   1998           Utils::ToLocal(Handle<JSObject>::cast(global_obj)));
   1999     } else {
   2000       urls[i] = NULL;
   2001     }
   2002   }
   2003 
   2004   DisallowHeapAllocation no_allocation;
   2005   for (int i = 0, l = enumerator.count(); i < l; ++i) {
   2006     objects_tags_.SetTag(*enumerator.at(i), urls[i]);
   2007   }
   2008 
   2009   DeleteArray(urls);
   2010 }
   2011 
   2012 
   2013 class GlobalHandlesExtractor : public ObjectVisitor {
   2014  public:
   2015   explicit GlobalHandlesExtractor(NativeObjectsExplorer* explorer)
   2016       : explorer_(explorer) {}
   2017   virtual ~GlobalHandlesExtractor() {}
   2018   virtual void VisitPointers(Object** start, Object** end) {
   2019     UNREACHABLE();
   2020   }
   2021   virtual void VisitEmbedderReference(Object** p, uint16_t class_id) {
   2022     explorer_->VisitSubtreeWrapper(p, class_id);
   2023   }
   2024  private:
   2025   NativeObjectsExplorer* explorer_;
   2026 };
   2027 
   2028 
   2029 class BasicHeapEntriesAllocator : public HeapEntriesAllocator {
   2030  public:
   2031   BasicHeapEntriesAllocator(
   2032       HeapSnapshot* snapshot,
   2033       HeapEntry::Type entries_type)
   2034     : snapshot_(snapshot),
   2035       names_(snapshot_->profiler()->names()),
   2036       heap_object_map_(snapshot_->profiler()->heap_object_map()),
   2037       entries_type_(entries_type) {
   2038   }
   2039   virtual HeapEntry* AllocateEntry(HeapThing ptr);
   2040  private:
   2041   HeapSnapshot* snapshot_;
   2042   StringsStorage* names_;
   2043   HeapObjectsMap* heap_object_map_;
   2044   HeapEntry::Type entries_type_;
   2045 };
   2046 
   2047 
   2048 HeapEntry* BasicHeapEntriesAllocator::AllocateEntry(HeapThing ptr) {
   2049   v8::RetainedObjectInfo* info = reinterpret_cast<v8::RetainedObjectInfo*>(ptr);
   2050   intptr_t elements = info->GetElementCount();
   2051   intptr_t size = info->GetSizeInBytes();
   2052   const char* name = elements != -1
   2053       ? names_->GetFormatted(
   2054             "%s / %" V8_PTR_PREFIX "d entries", info->GetLabel(), elements)
   2055       : names_->GetCopy(info->GetLabel());
   2056   return snapshot_->AddEntry(
   2057       entries_type_,
   2058       name,
   2059       heap_object_map_->GenerateId(info),
   2060       size != -1 ? static_cast<int>(size) : 0);
   2061 }
   2062 
   2063 
   2064 NativeObjectsExplorer::NativeObjectsExplorer(
   2065     HeapSnapshot* snapshot,
   2066     SnapshottingProgressReportingInterface* progress)
   2067     : isolate_(snapshot->profiler()->heap_object_map()->heap()->isolate()),
   2068       snapshot_(snapshot),
   2069       names_(snapshot_->profiler()->names()),
   2070       progress_(progress),
   2071       embedder_queried_(false),
   2072       objects_by_info_(RetainedInfosMatch),
   2073       native_groups_(StringsMatch),
   2074       filler_(NULL) {
   2075   synthetic_entries_allocator_ =
   2076       new BasicHeapEntriesAllocator(snapshot, HeapEntry::kSynthetic);
   2077   native_entries_allocator_ =
   2078       new BasicHeapEntriesAllocator(snapshot, HeapEntry::kNative);
   2079 }
   2080 
   2081 
   2082 NativeObjectsExplorer::~NativeObjectsExplorer() {
   2083   for (HashMap::Entry* p = objects_by_info_.Start();
   2084        p != NULL;
   2085        p = objects_by_info_.Next(p)) {
   2086     v8::RetainedObjectInfo* info =
   2087         reinterpret_cast<v8::RetainedObjectInfo*>(p->key);
   2088     info->Dispose();
   2089     List<HeapObject*>* objects =
   2090         reinterpret_cast<List<HeapObject*>* >(p->value);
   2091     delete objects;
   2092   }
   2093   for (HashMap::Entry* p = native_groups_.Start();
   2094        p != NULL;
   2095        p = native_groups_.Next(p)) {
   2096     v8::RetainedObjectInfo* info =
   2097         reinterpret_cast<v8::RetainedObjectInfo*>(p->value);
   2098     info->Dispose();
   2099   }
   2100   delete synthetic_entries_allocator_;
   2101   delete native_entries_allocator_;
   2102 }
   2103 
   2104 
   2105 int NativeObjectsExplorer::EstimateObjectsCount() {
   2106   FillRetainedObjects();
   2107   return objects_by_info_.occupancy();
   2108 }
   2109 
   2110 
   2111 void NativeObjectsExplorer::FillRetainedObjects() {
   2112   if (embedder_queried_) return;
   2113   Isolate* isolate = isolate_;
   2114   const GCType major_gc_type = kGCTypeMarkSweepCompact;
   2115   // Record objects that are joined into ObjectGroups.
   2116   isolate->heap()->CallGCPrologueCallbacks(
   2117       major_gc_type, kGCCallbackFlagConstructRetainedObjectInfos);
   2118   List<ObjectGroup*>* groups = isolate->global_handles()->object_groups();
   2119   for (int i = 0; i < groups->length(); ++i) {
   2120     ObjectGroup* group = groups->at(i);
   2121     if (group->info == NULL) continue;
   2122     List<HeapObject*>* list = GetListMaybeDisposeInfo(group->info);
   2123     for (size_t j = 0; j < group->length; ++j) {
   2124       HeapObject* obj = HeapObject::cast(*group->objects[j]);
   2125       list->Add(obj);
   2126       in_groups_.Insert(obj);
   2127     }
   2128     group->info = NULL;  // Acquire info object ownership.
   2129   }
   2130   isolate->global_handles()->RemoveObjectGroups();
   2131   isolate->heap()->CallGCEpilogueCallbacks(major_gc_type);
   2132   // Record objects that are not in ObjectGroups, but have class ID.
   2133   GlobalHandlesExtractor extractor(this);
   2134   isolate->global_handles()->IterateAllRootsWithClassIds(&extractor);
   2135   embedder_queried_ = true;
   2136 }
   2137 
   2138 
   2139 void NativeObjectsExplorer::FillImplicitReferences() {
   2140   Isolate* isolate = isolate_;
   2141   List<ImplicitRefGroup*>* groups =
   2142       isolate->global_handles()->implicit_ref_groups();
   2143   for (int i = 0; i < groups->length(); ++i) {
   2144     ImplicitRefGroup* group = groups->at(i);
   2145     HeapObject* parent = *group->parent;
   2146     int parent_entry =
   2147         filler_->FindOrAddEntry(parent, native_entries_allocator_)->index();
   2148     ASSERT(parent_entry != HeapEntry::kNoEntry);
   2149     Object*** children = group->children;
   2150     for (size_t j = 0; j < group->length; ++j) {
   2151       Object* child = *children[j];
   2152       HeapEntry* child_entry =
   2153           filler_->FindOrAddEntry(child, native_entries_allocator_);
   2154       filler_->SetNamedReference(
   2155           HeapGraphEdge::kInternal,
   2156           parent_entry,
   2157           "native",
   2158           child_entry);
   2159     }
   2160   }
   2161   isolate->global_handles()->RemoveImplicitRefGroups();
   2162 }
   2163 
   2164 List<HeapObject*>* NativeObjectsExplorer::GetListMaybeDisposeInfo(
   2165     v8::RetainedObjectInfo* info) {
   2166   HashMap::Entry* entry =
   2167       objects_by_info_.Lookup(info, InfoHash(info), true);
   2168   if (entry->value != NULL) {
   2169     info->Dispose();
   2170   } else {
   2171     entry->value = new List<HeapObject*>(4);
   2172   }
   2173   return reinterpret_cast<List<HeapObject*>* >(entry->value);
   2174 }
   2175 
   2176 
   2177 bool NativeObjectsExplorer::IterateAndExtractReferences(
   2178     SnapshotFillerInterface* filler) {
   2179   filler_ = filler;
   2180   FillRetainedObjects();
   2181   FillImplicitReferences();
   2182   if (EstimateObjectsCount() > 0) {
   2183     for (HashMap::Entry* p = objects_by_info_.Start();
   2184          p != NULL;
   2185          p = objects_by_info_.Next(p)) {
   2186       v8::RetainedObjectInfo* info =
   2187           reinterpret_cast<v8::RetainedObjectInfo*>(p->key);
   2188       SetNativeRootReference(info);
   2189       List<HeapObject*>* objects =
   2190           reinterpret_cast<List<HeapObject*>* >(p->value);
   2191       for (int i = 0; i < objects->length(); ++i) {
   2192         SetWrapperNativeReferences(objects->at(i), info);
   2193       }
   2194     }
   2195     SetRootNativeRootsReference();
   2196   }
   2197   filler_ = NULL;
   2198   return true;
   2199 }
   2200 
   2201 
   2202 class NativeGroupRetainedObjectInfo : public v8::RetainedObjectInfo {
   2203  public:
   2204   explicit NativeGroupRetainedObjectInfo(const char* label)
   2205       : disposed_(false),
   2206         hash_(reinterpret_cast<intptr_t>(label)),
   2207         label_(label) {
   2208   }
   2209 
   2210   virtual ~NativeGroupRetainedObjectInfo() {}
   2211   virtual void Dispose() {
   2212     CHECK(!disposed_);
   2213     disposed_ = true;
   2214     delete this;
   2215   }
   2216   virtual bool IsEquivalent(RetainedObjectInfo* other) {
   2217     return hash_ == other->GetHash() && !strcmp(label_, other->GetLabel());
   2218   }
   2219   virtual intptr_t GetHash() { return hash_; }
   2220   virtual const char* GetLabel() { return label_; }
   2221 
   2222  private:
   2223   bool disposed_;
   2224   intptr_t hash_;
   2225   const char* label_;
   2226 };
   2227 
   2228 
   2229 NativeGroupRetainedObjectInfo* NativeObjectsExplorer::FindOrAddGroupInfo(
   2230     const char* label) {
   2231   const char* label_copy = names_->GetCopy(label);
   2232   uint32_t hash = StringHasher::HashSequentialString(
   2233       label_copy,
   2234       static_cast<int>(strlen(label_copy)),
   2235       isolate_->heap()->HashSeed());
   2236   HashMap::Entry* entry = native_groups_.Lookup(const_cast<char*>(label_copy),
   2237                                                 hash, true);
   2238   if (entry->value == NULL) {
   2239     entry->value = new NativeGroupRetainedObjectInfo(label);
   2240   }
   2241   return static_cast<NativeGroupRetainedObjectInfo*>(entry->value);
   2242 }
   2243 
   2244 
   2245 void NativeObjectsExplorer::SetNativeRootReference(
   2246     v8::RetainedObjectInfo* info) {
   2247   HeapEntry* child_entry =
   2248       filler_->FindOrAddEntry(info, native_entries_allocator_);
   2249   ASSERT(child_entry != NULL);
   2250   NativeGroupRetainedObjectInfo* group_info =
   2251       FindOrAddGroupInfo(info->GetGroupLabel());
   2252   HeapEntry* group_entry =
   2253       filler_->FindOrAddEntry(group_info, synthetic_entries_allocator_);
   2254   filler_->SetNamedAutoIndexReference(
   2255       HeapGraphEdge::kInternal,
   2256       group_entry->index(),
   2257       child_entry);
   2258 }
   2259 
   2260 
   2261 void NativeObjectsExplorer::SetWrapperNativeReferences(
   2262     HeapObject* wrapper, v8::RetainedObjectInfo* info) {
   2263   HeapEntry* wrapper_entry = filler_->FindEntry(wrapper);
   2264   ASSERT(wrapper_entry != NULL);
   2265   HeapEntry* info_entry =
   2266       filler_->FindOrAddEntry(info, native_entries_allocator_);
   2267   ASSERT(info_entry != NULL);
   2268   filler_->SetNamedReference(HeapGraphEdge::kInternal,
   2269                              wrapper_entry->index(),
   2270                              "native",
   2271                              info_entry);
   2272   filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
   2273                                         info_entry->index(),
   2274                                         wrapper_entry);
   2275 }
   2276 
   2277 
   2278 void NativeObjectsExplorer::SetRootNativeRootsReference() {
   2279   for (HashMap::Entry* entry = native_groups_.Start();
   2280        entry;
   2281        entry = native_groups_.Next(entry)) {
   2282     NativeGroupRetainedObjectInfo* group_info =
   2283         static_cast<NativeGroupRetainedObjectInfo*>(entry->value);
   2284     HeapEntry* group_entry =
   2285         filler_->FindOrAddEntry(group_info, native_entries_allocator_);
   2286     ASSERT(group_entry != NULL);
   2287     filler_->SetIndexedAutoIndexReference(
   2288         HeapGraphEdge::kElement,
   2289         snapshot_->root()->index(),
   2290         group_entry);
   2291   }
   2292 }
   2293 
   2294 
   2295 void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) {
   2296   if (in_groups_.Contains(*p)) return;
   2297   Isolate* isolate = isolate_;
   2298   v8::RetainedObjectInfo* info =
   2299       isolate->heap_profiler()->ExecuteWrapperClassCallback(class_id, p);
   2300   if (info == NULL) return;
   2301   GetListMaybeDisposeInfo(info)->Add(HeapObject::cast(*p));
   2302 }
   2303 
   2304 
   2305 class SnapshotFiller : public SnapshotFillerInterface {
   2306  public:
   2307   explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries)
   2308       : snapshot_(snapshot),
   2309         names_(snapshot->profiler()->names()),
   2310         entries_(entries) { }
   2311   HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
   2312     HeapEntry* entry = allocator->AllocateEntry(ptr);
   2313     entries_->Pair(ptr, entry->index());
   2314     return entry;
   2315   }
   2316   HeapEntry* FindEntry(HeapThing ptr) {
   2317     int index = entries_->Map(ptr);
   2318     return index != HeapEntry::kNoEntry ? &snapshot_->entries()[index] : NULL;
   2319   }
   2320   HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
   2321     HeapEntry* entry = FindEntry(ptr);
   2322     return entry != NULL ? entry : AddEntry(ptr, allocator);
   2323   }
   2324   void SetIndexedReference(HeapGraphEdge::Type type,
   2325                            int parent,
   2326                            int index,
   2327                            HeapEntry* child_entry) {
   2328     HeapEntry* parent_entry = &snapshot_->entries()[parent];
   2329     parent_entry->SetIndexedReference(type, index, child_entry);
   2330   }
   2331   void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
   2332                                     int parent,
   2333                                     HeapEntry* child_entry) {
   2334     HeapEntry* parent_entry = &snapshot_->entries()[parent];
   2335     int index = parent_entry->children_count() + 1;
   2336     parent_entry->SetIndexedReference(type, index, child_entry);
   2337   }
   2338   void SetNamedReference(HeapGraphEdge::Type type,
   2339                          int parent,
   2340                          const char* reference_name,
   2341                          HeapEntry* child_entry) {
   2342     HeapEntry* parent_entry = &snapshot_->entries()[parent];
   2343     parent_entry->SetNamedReference(type, reference_name, child_entry);
   2344   }
   2345   void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
   2346                                   int parent,
   2347                                   HeapEntry* child_entry) {
   2348     HeapEntry* parent_entry = &snapshot_->entries()[parent];
   2349     int index = parent_entry->children_count() + 1;
   2350     parent_entry->SetNamedReference(
   2351         type,
   2352         names_->GetName(index),
   2353         child_entry);
   2354   }
   2355 
   2356  private:
   2357   HeapSnapshot* snapshot_;
   2358   StringsStorage* names_;
   2359   HeapEntriesMap* entries_;
   2360 };
   2361 
   2362 
   2363 HeapSnapshotGenerator::HeapSnapshotGenerator(
   2364     HeapSnapshot* snapshot,
   2365     v8::ActivityControl* control,
   2366     v8::HeapProfiler::ObjectNameResolver* resolver,
   2367     Heap* heap)
   2368     : snapshot_(snapshot),
   2369       control_(control),
   2370       v8_heap_explorer_(snapshot_, this, resolver),
   2371       dom_explorer_(snapshot_, this),
   2372       heap_(heap) {
   2373 }
   2374 
   2375 
   2376 bool HeapSnapshotGenerator::GenerateSnapshot() {
   2377   v8_heap_explorer_.TagGlobalObjects();
   2378 
   2379   // TODO(1562) Profiler assumes that any object that is in the heap after
   2380   // full GC is reachable from the root when computing dominators.
   2381   // This is not true for weakly reachable objects.
   2382   // As a temporary solution we call GC twice.
   2383   heap_->CollectAllGarbage(
   2384       Heap::kMakeHeapIterableMask,
   2385       "HeapSnapshotGenerator::GenerateSnapshot");
   2386   heap_->CollectAllGarbage(
   2387       Heap::kMakeHeapIterableMask,
   2388       "HeapSnapshotGenerator::GenerateSnapshot");
   2389 
   2390 #ifdef VERIFY_HEAP
   2391   Heap* debug_heap = heap_;
   2392   CHECK(!debug_heap->old_data_space()->was_swept_conservatively());
   2393   CHECK(!debug_heap->old_pointer_space()->was_swept_conservatively());
   2394   CHECK(!debug_heap->code_space()->was_swept_conservatively());
   2395   CHECK(!debug_heap->cell_space()->was_swept_conservatively());
   2396   CHECK(!debug_heap->property_cell_space()->
   2397         was_swept_conservatively());
   2398   CHECK(!debug_heap->map_space()->was_swept_conservatively());
   2399 #endif
   2400 
   2401   // The following code uses heap iterators, so we want the heap to be
   2402   // stable. It should follow TagGlobalObjects as that can allocate.
   2403   DisallowHeapAllocation no_alloc;
   2404 
   2405 #ifdef VERIFY_HEAP
   2406   debug_heap->Verify();
   2407 #endif
   2408 
   2409   SetProgressTotal(1);  // 1 pass.
   2410 
   2411 #ifdef VERIFY_HEAP
   2412   debug_heap->Verify();
   2413 #endif
   2414 
   2415   if (!FillReferences()) return false;
   2416 
   2417   snapshot_->FillChildren();
   2418   snapshot_->RememberLastJSObjectId();
   2419 
   2420   progress_counter_ = progress_total_;
   2421   if (!ProgressReport(true)) return false;
   2422   return true;
   2423 }
   2424 
   2425 
   2426 void HeapSnapshotGenerator::ProgressStep() {
   2427   ++progress_counter_;
   2428 }
   2429 
   2430 
   2431 bool HeapSnapshotGenerator::ProgressReport(bool force) {
   2432   const int kProgressReportGranularity = 10000;
   2433   if (control_ != NULL
   2434       && (force || progress_counter_ % kProgressReportGranularity == 0)) {
   2435       return
   2436           control_->ReportProgressValue(progress_counter_, progress_total_) ==
   2437           v8::ActivityControl::kContinue;
   2438   }
   2439   return true;
   2440 }
   2441 
   2442 
   2443 void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
   2444   if (control_ == NULL) return;
   2445   HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable);
   2446   progress_total_ = iterations_count * (
   2447       v8_heap_explorer_.EstimateObjectsCount(&iterator) +
   2448       dom_explorer_.EstimateObjectsCount());
   2449   progress_counter_ = 0;
   2450 }
   2451 
   2452 
   2453 bool HeapSnapshotGenerator::FillReferences() {
   2454   SnapshotFiller filler(snapshot_, &entries_);
   2455   v8_heap_explorer_.AddRootEntries(&filler);
   2456   return v8_heap_explorer_.IterateAndExtractReferences(&filler)
   2457       && dom_explorer_.IterateAndExtractReferences(&filler);
   2458 }
   2459 
   2460 
   2461 template<int bytes> struct MaxDecimalDigitsIn;
   2462 template<> struct MaxDecimalDigitsIn<4> {
   2463   static const int kSigned = 11;
   2464   static const int kUnsigned = 10;
   2465 };
   2466 template<> struct MaxDecimalDigitsIn<8> {
   2467   static const int kSigned = 20;
   2468   static const int kUnsigned = 20;
   2469 };
   2470 
   2471 
   2472 class OutputStreamWriter {
   2473  public:
   2474   explicit OutputStreamWriter(v8::OutputStream* stream)
   2475       : stream_(stream),
   2476         chunk_size_(stream->GetChunkSize()),
   2477         chunk_(chunk_size_),
   2478         chunk_pos_(0),
   2479         aborted_(false) {
   2480     ASSERT(chunk_size_ > 0);
   2481   }
   2482   bool aborted() { return aborted_; }
   2483   void AddCharacter(char c) {
   2484     ASSERT(c != '\0');
   2485     ASSERT(chunk_pos_ < chunk_size_);
   2486     chunk_[chunk_pos_++] = c;
   2487     MaybeWriteChunk();
   2488   }
   2489   void AddString(const char* s) {
   2490     AddSubstring(s, StrLength(s));
   2491   }
   2492   void AddSubstring(const char* s, int n) {
   2493     if (n <= 0) return;
   2494     ASSERT(static_cast<size_t>(n) <= strlen(s));
   2495     const char* s_end = s + n;
   2496     while (s < s_end) {
   2497       int s_chunk_size = Min(
   2498           chunk_size_ - chunk_pos_, static_cast<int>(s_end - s));
   2499       ASSERT(s_chunk_size > 0);
   2500       OS::MemCopy(chunk_.start() + chunk_pos_, s, s_chunk_size);
   2501       s += s_chunk_size;
   2502       chunk_pos_ += s_chunk_size;
   2503       MaybeWriteChunk();
   2504     }
   2505   }
   2506   void AddNumber(unsigned n) { AddNumberImpl<unsigned>(n, "%u"); }
   2507   void Finalize() {
   2508     if (aborted_) return;
   2509     ASSERT(chunk_pos_ < chunk_size_);
   2510     if (chunk_pos_ != 0) {
   2511       WriteChunk();
   2512     }
   2513     stream_->EndOfStream();
   2514   }
   2515 
   2516  private:
   2517   template<typename T>
   2518   void AddNumberImpl(T n, const char* format) {
   2519     // Buffer for the longest value plus trailing \0
   2520     static const int kMaxNumberSize =
   2521         MaxDecimalDigitsIn<sizeof(T)>::kUnsigned + 1;
   2522     if (chunk_size_ - chunk_pos_ >= kMaxNumberSize) {
   2523       int result = OS::SNPrintF(
   2524           chunk_.SubVector(chunk_pos_, chunk_size_), format, n);
   2525       ASSERT(result != -1);
   2526       chunk_pos_ += result;
   2527       MaybeWriteChunk();
   2528     } else {
   2529       EmbeddedVector<char, kMaxNumberSize> buffer;
   2530       int result = OS::SNPrintF(buffer, format, n);
   2531       USE(result);
   2532       ASSERT(result != -1);
   2533       AddString(buffer.start());
   2534     }
   2535   }
   2536   void MaybeWriteChunk() {
   2537     ASSERT(chunk_pos_ <= chunk_size_);
   2538     if (chunk_pos_ == chunk_size_) {
   2539       WriteChunk();
   2540     }
   2541   }
   2542   void WriteChunk() {
   2543     if (aborted_) return;
   2544     if (stream_->WriteAsciiChunk(chunk_.start(), chunk_pos_) ==
   2545         v8::OutputStream::kAbort) aborted_ = true;
   2546     chunk_pos_ = 0;
   2547   }
   2548 
   2549   v8::OutputStream* stream_;
   2550   int chunk_size_;
   2551   ScopedVector<char> chunk_;
   2552   int chunk_pos_;
   2553   bool aborted_;
   2554 };
   2555 
   2556 
   2557 // type, name|index, to_node.
   2558 const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3;
   2559 // type, name, id, self_size, children_index.
   2560 const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 5;
   2561 
   2562 void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
   2563   if (AllocationTracker* allocation_tracker =
   2564       snapshot_->profiler()->allocation_tracker()) {
   2565     allocation_tracker->PrepareForSerialization();
   2566   }
   2567   ASSERT(writer_ == NULL);
   2568   writer_ = new OutputStreamWriter(stream);
   2569   SerializeImpl();
   2570   delete writer_;
   2571   writer_ = NULL;
   2572 }
   2573 
   2574 
   2575 void HeapSnapshotJSONSerializer::SerializeImpl() {
   2576   ASSERT(0 == snapshot_->root()->index());
   2577   writer_->AddCharacter('{');
   2578   writer_->AddString("\"snapshot\":{");
   2579   SerializeSnapshot();
   2580   if (writer_->aborted()) return;
   2581   writer_->AddString("},\n");
   2582   writer_->AddString("\"nodes\":[");
   2583   SerializeNodes();
   2584   if (writer_->aborted()) return;
   2585   writer_->AddString("],\n");
   2586   writer_->AddString("\"edges\":[");
   2587   SerializeEdges();
   2588   if (writer_->aborted()) return;
   2589   writer_->AddString("],\n");
   2590 
   2591   writer_->AddString("\"trace_function_infos\":[");
   2592   SerializeTraceNodeInfos();
   2593   if (writer_->aborted()) return;
   2594   writer_->AddString("],\n");
   2595   writer_->AddString("\"trace_tree\":[");
   2596   SerializeTraceTree();
   2597   if (writer_->aborted()) return;
   2598   writer_->AddString("],\n");
   2599 
   2600   writer_->AddString("\"strings\":[");
   2601   SerializeStrings();
   2602   if (writer_->aborted()) return;
   2603   writer_->AddCharacter(']');
   2604   writer_->AddCharacter('}');
   2605   writer_->Finalize();
   2606 }
   2607 
   2608 
   2609 int HeapSnapshotJSONSerializer::GetStringId(const char* s) {
   2610   HashMap::Entry* cache_entry = strings_.Lookup(
   2611       const_cast<char*>(s), StringHash(s), true);
   2612   if (cache_entry->value == NULL) {
   2613     cache_entry->value = reinterpret_cast<void*>(next_string_id_++);
   2614   }
   2615   return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value));
   2616 }
   2617 
   2618 
   2619 static int utoa(unsigned value, const Vector<char>& buffer, int buffer_pos) {
   2620   int number_of_digits = 0;
   2621   unsigned t = value;
   2622   do {
   2623     ++number_of_digits;
   2624   } while (t /= 10);
   2625 
   2626   buffer_pos += number_of_digits;
   2627   int result = buffer_pos;
   2628   do {
   2629     int last_digit = value % 10;
   2630     buffer[--buffer_pos] = '0' + last_digit;
   2631     value /= 10;
   2632   } while (value);
   2633   return result;
   2634 }
   2635 
   2636 
   2637 void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
   2638                                                bool first_edge) {
   2639   // The buffer needs space for 3 unsigned ints, 3 commas, \n and \0
   2640   static const int kBufferSize =
   2641       MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned * 3 + 3 + 2;  // NOLINT
   2642   EmbeddedVector<char, kBufferSize> buffer;
   2643   int edge_name_or_index = edge->type() == HeapGraphEdge::kElement
   2644       || edge->type() == HeapGraphEdge::kHidden
   2645       || edge->type() == HeapGraphEdge::kWeak
   2646       ? edge->index() : GetStringId(edge->name());
   2647   int buffer_pos = 0;
   2648   if (!first_edge) {
   2649     buffer[buffer_pos++] = ',';
   2650   }
   2651   buffer_pos = utoa(edge->type(), buffer, buffer_pos);
   2652   buffer[buffer_pos++] = ',';
   2653   buffer_pos = utoa(edge_name_or_index, buffer, buffer_pos);
   2654   buffer[buffer_pos++] = ',';
   2655   buffer_pos = utoa(entry_index(edge->to()), buffer, buffer_pos);
   2656   buffer[buffer_pos++] = '\n';
   2657   buffer[buffer_pos++] = '\0';
   2658   writer_->AddString(buffer.start());
   2659 }
   2660 
   2661 
   2662 void HeapSnapshotJSONSerializer::SerializeEdges() {
   2663   List<HeapGraphEdge*>& edges = snapshot_->children();
   2664   for (int i = 0; i < edges.length(); ++i) {
   2665     ASSERT(i == 0 ||
   2666            edges[i - 1]->from()->index() <= edges[i]->from()->index());
   2667     SerializeEdge(edges[i], i == 0);
   2668     if (writer_->aborted()) return;
   2669   }
   2670 }
   2671 
   2672 
   2673 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
   2674   // The buffer needs space for 5 unsigned ints, 5 commas, \n and \0
   2675   static const int kBufferSize =
   2676       5 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
   2677       + 5 + 1 + 1;
   2678   EmbeddedVector<char, kBufferSize> buffer;
   2679   int buffer_pos = 0;
   2680   if (entry_index(entry) != 0) {
   2681     buffer[buffer_pos++] = ',';
   2682   }
   2683   buffer_pos = utoa(entry->type(), buffer, buffer_pos);
   2684   buffer[buffer_pos++] = ',';
   2685   buffer_pos = utoa(GetStringId(entry->name()), buffer, buffer_pos);
   2686   buffer[buffer_pos++] = ',';
   2687   buffer_pos = utoa(entry->id(), buffer, buffer_pos);
   2688   buffer[buffer_pos++] = ',';
   2689   buffer_pos = utoa(entry->self_size(), buffer, buffer_pos);
   2690   buffer[buffer_pos++] = ',';
   2691   buffer_pos = utoa(entry->children_count(), buffer, buffer_pos);
   2692   buffer[buffer_pos++] = '\n';
   2693   buffer[buffer_pos++] = '\0';
   2694   writer_->AddString(buffer.start());
   2695 }
   2696 
   2697 
   2698 void HeapSnapshotJSONSerializer::SerializeNodes() {
   2699   List<HeapEntry>& entries = snapshot_->entries();
   2700   for (int i = 0; i < entries.length(); ++i) {
   2701     SerializeNode(&entries[i]);
   2702     if (writer_->aborted()) return;
   2703   }
   2704 }
   2705 
   2706 
   2707 void HeapSnapshotJSONSerializer::SerializeSnapshot() {
   2708   writer_->AddString("\"title\":\"");
   2709   writer_->AddString(snapshot_->title());
   2710   writer_->AddString("\"");
   2711   writer_->AddString(",\"uid\":");
   2712   writer_->AddNumber(snapshot_->uid());
   2713   writer_->AddString(",\"meta\":");
   2714   // The object describing node serialization layout.
   2715   // We use a set of macros to improve readability.
   2716 #define JSON_A(s) "[" s "]"
   2717 #define JSON_O(s) "{" s "}"
   2718 #define JSON_S(s) "\"" s "\""
   2719   writer_->AddString(JSON_O(
   2720     JSON_S("node_fields") ":" JSON_A(
   2721         JSON_S("type") ","
   2722         JSON_S("name") ","
   2723         JSON_S("id") ","
   2724         JSON_S("self_size") ","
   2725         JSON_S("edge_count")) ","
   2726     JSON_S("node_types") ":" JSON_A(
   2727         JSON_A(
   2728             JSON_S("hidden") ","
   2729             JSON_S("array") ","
   2730             JSON_S("string") ","
   2731             JSON_S("object") ","
   2732             JSON_S("code") ","
   2733             JSON_S("closure") ","
   2734             JSON_S("regexp") ","
   2735             JSON_S("number") ","
   2736             JSON_S("native") ","
   2737             JSON_S("synthetic") ","
   2738             JSON_S("concatenated string") ","
   2739             JSON_S("sliced string")) ","
   2740         JSON_S("string") ","
   2741         JSON_S("number") ","
   2742         JSON_S("number") ","
   2743         JSON_S("number") ","
   2744         JSON_S("number") ","
   2745         JSON_S("number")) ","
   2746     JSON_S("edge_fields") ":" JSON_A(
   2747         JSON_S("type") ","
   2748         JSON_S("name_or_index") ","
   2749         JSON_S("to_node")) ","
   2750     JSON_S("edge_types") ":" JSON_A(
   2751         JSON_A(
   2752             JSON_S("context") ","
   2753             JSON_S("element") ","
   2754             JSON_S("property") ","
   2755             JSON_S("internal") ","
   2756             JSON_S("hidden") ","
   2757             JSON_S("shortcut") ","
   2758             JSON_S("weak")) ","
   2759         JSON_S("string_or_number") ","
   2760         JSON_S("node")) ","
   2761     JSON_S("trace_function_info_fields") ":" JSON_A(
   2762         JSON_S("function_id") ","
   2763         JSON_S("name") ","
   2764         JSON_S("script_name") ","
   2765         JSON_S("script_id") ","
   2766         JSON_S("line") ","
   2767         JSON_S("column")) ","
   2768     JSON_S("trace_node_fields") ":" JSON_A(
   2769         JSON_S("id") ","
   2770         JSON_S("function_id") ","
   2771         JSON_S("count") ","
   2772         JSON_S("size") ","
   2773         JSON_S("children"))));
   2774 #undef JSON_S
   2775 #undef JSON_O
   2776 #undef JSON_A
   2777   writer_->AddString(",\"node_count\":");
   2778   writer_->AddNumber(snapshot_->entries().length());
   2779   writer_->AddString(",\"edge_count\":");
   2780   writer_->AddNumber(snapshot_->edges().length());
   2781   writer_->AddString(",\"trace_function_count\":");
   2782   uint32_t count = 0;
   2783   AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker();
   2784   if (tracker) {
   2785     count = tracker->id_to_function_info()->occupancy();
   2786   }
   2787   writer_->AddNumber(count);
   2788 }
   2789 
   2790 
   2791 static void WriteUChar(OutputStreamWriter* w, unibrow::uchar u) {
   2792   static const char hex_chars[] = "0123456789ABCDEF";
   2793   w->AddString("\\u");
   2794   w->AddCharacter(hex_chars[(u >> 12) & 0xf]);
   2795   w->AddCharacter(hex_chars[(u >> 8) & 0xf]);
   2796   w->AddCharacter(hex_chars[(u >> 4) & 0xf]);
   2797   w->AddCharacter(hex_chars[u & 0xf]);
   2798 }
   2799 
   2800 
   2801 void HeapSnapshotJSONSerializer::SerializeTraceTree() {
   2802   AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker();
   2803   if (!tracker) return;
   2804   AllocationTraceTree* traces = tracker->trace_tree();
   2805   SerializeTraceNode(traces->root());
   2806 }
   2807 
   2808 
   2809 void HeapSnapshotJSONSerializer::SerializeTraceNode(AllocationTraceNode* node) {
   2810   // The buffer needs space for 4 unsigned ints, 4 commas, [ and \0
   2811   const int kBufferSize =
   2812       4 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
   2813       + 4 + 1 + 1;
   2814   EmbeddedVector<char, kBufferSize> buffer;
   2815   int buffer_pos = 0;
   2816   buffer_pos = utoa(node->id(), buffer, buffer_pos);
   2817   buffer[buffer_pos++] = ',';
   2818   buffer_pos = utoa(node->function_id(), buffer, buffer_pos);
   2819   buffer[buffer_pos++] = ',';
   2820   buffer_pos = utoa(node->allocation_count(), buffer, buffer_pos);
   2821   buffer[buffer_pos++] = ',';
   2822   buffer_pos = utoa(node->allocation_size(), buffer, buffer_pos);
   2823   buffer[buffer_pos++] = ',';
   2824   buffer[buffer_pos++] = '[';
   2825   buffer[buffer_pos++] = '\0';
   2826   writer_->AddString(buffer.start());
   2827 
   2828   Vector<AllocationTraceNode*> children = node->children();
   2829   for (int i = 0; i < children.length(); i++) {
   2830     if (i > 0) {
   2831       writer_->AddCharacter(',');
   2832     }
   2833     SerializeTraceNode(children[i]);
   2834   }
   2835   writer_->AddCharacter(']');
   2836 }
   2837 
   2838 
   2839 // 0-based position is converted to 1-based during the serialization.
   2840 static int SerializePosition(int position, const Vector<char>& buffer,
   2841                              int buffer_pos) {
   2842   if (position == -1) {
   2843     buffer[buffer_pos++] = '0';
   2844   } else {
   2845     ASSERT(position >= 0);
   2846     buffer_pos = utoa(static_cast<unsigned>(position + 1), buffer, buffer_pos);
   2847   }
   2848   return buffer_pos;
   2849 }
   2850 
   2851 
   2852 void HeapSnapshotJSONSerializer::SerializeTraceNodeInfos() {
   2853   AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker();
   2854   if (!tracker) return;
   2855   // The buffer needs space for 6 unsigned ints, 6 commas, \n and \0
   2856   const int kBufferSize =
   2857       6 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
   2858       + 6 + 1 + 1;
   2859   EmbeddedVector<char, kBufferSize> buffer;
   2860   HashMap* id_to_function_info = tracker->id_to_function_info();
   2861   bool first_entry = true;
   2862   for (HashMap::Entry* p = id_to_function_info->Start();
   2863        p != NULL;
   2864        p = id_to_function_info->Next(p)) {
   2865     SnapshotObjectId id =
   2866         static_cast<SnapshotObjectId>(reinterpret_cast<intptr_t>(p->key));
   2867     AllocationTracker::FunctionInfo* info =
   2868         reinterpret_cast<AllocationTracker::FunctionInfo* >(p->value);
   2869     int buffer_pos = 0;
   2870     if (first_entry) {
   2871       first_entry = false;
   2872     } else {
   2873       buffer[buffer_pos++] = ',';
   2874     }
   2875     buffer_pos = utoa(id, buffer, buffer_pos);
   2876     buffer[buffer_pos++] = ',';
   2877     buffer_pos = utoa(GetStringId(info->name), buffer, buffer_pos);
   2878     buffer[buffer_pos++] = ',';
   2879     buffer_pos = utoa(GetStringId(info->script_name), buffer, buffer_pos);
   2880     buffer[buffer_pos++] = ',';
   2881     // The cast is safe because script id is a non-negative Smi.
   2882     buffer_pos = utoa(static_cast<unsigned>(info->script_id), buffer,
   2883         buffer_pos);
   2884     buffer[buffer_pos++] = ',';
   2885     buffer_pos = SerializePosition(info->line, buffer, buffer_pos);
   2886     buffer[buffer_pos++] = ',';
   2887     buffer_pos = SerializePosition(info->column, buffer, buffer_pos);
   2888     buffer[buffer_pos++] = '\n';
   2889     buffer[buffer_pos++] = '\0';
   2890     writer_->AddString(buffer.start());
   2891   }
   2892 }
   2893 
   2894 
   2895 void HeapSnapshotJSONSerializer::SerializeString(const unsigned char* s) {
   2896   writer_->AddCharacter('\n');
   2897   writer_->AddCharacter('\"');
   2898   for ( ; *s != '\0'; ++s) {
   2899     switch (*s) {
   2900       case '\b':
   2901         writer_->AddString("\\b");
   2902         continue;
   2903       case '\f':
   2904         writer_->AddString("\\f");
   2905         continue;
   2906       case '\n':
   2907         writer_->AddString("\\n");
   2908         continue;
   2909       case '\r':
   2910         writer_->AddString("\\r");
   2911         continue;
   2912       case '\t':
   2913         writer_->AddString("\\t");
   2914         continue;
   2915       case '\"':
   2916       case '\\':
   2917         writer_->AddCharacter('\\');
   2918         writer_->AddCharacter(*s);
   2919         continue;
   2920       default:
   2921         if (*s > 31 && *s < 128) {
   2922           writer_->AddCharacter(*s);
   2923         } else if (*s <= 31) {
   2924           // Special character with no dedicated literal.
   2925           WriteUChar(writer_, *s);
   2926         } else {
   2927           // Convert UTF-8 into \u UTF-16 literal.
   2928           unsigned length = 1, cursor = 0;
   2929           for ( ; length <= 4 && *(s + length) != '\0'; ++length) { }
   2930           unibrow::uchar c = unibrow::Utf8::CalculateValue(s, length, &cursor);
   2931           if (c != unibrow::Utf8::kBadChar) {
   2932             WriteUChar(writer_, c);
   2933             ASSERT(cursor != 0);
   2934             s += cursor - 1;
   2935           } else {
   2936             writer_->AddCharacter('?');
   2937           }
   2938         }
   2939     }
   2940   }
   2941   writer_->AddCharacter('\"');
   2942 }
   2943 
   2944 
   2945 void HeapSnapshotJSONSerializer::SerializeStrings() {
   2946   ScopedVector<const unsigned char*> sorted_strings(
   2947       strings_.occupancy() + 1);
   2948   for (HashMap::Entry* entry = strings_.Start();
   2949        entry != NULL;
   2950        entry = strings_.Next(entry)) {
   2951     int index = static_cast<int>(reinterpret_cast<uintptr_t>(entry->value));
   2952     sorted_strings[index] = reinterpret_cast<const unsigned char*>(entry->key);
   2953   }
   2954   writer_->AddString("\"<dummy>\"");
   2955   for (int i = 1; i < sorted_strings.length(); ++i) {
   2956     writer_->AddCharacter(',');
   2957     SerializeString(sorted_strings[i]);
   2958     if (writer_->aborted()) return;
   2959   }
   2960 }
   2961 
   2962 
   2963 } }  // namespace v8::internal
   2964