LCOV - code coverage report
Current view: top level - src/profiler - heap-snapshot-generator.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1071 1237 86.6 %
Date: 2019-02-19 Functions: 128 163 78.5 %

          Line data    Source code
       1             : // Copyright 2013 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/profiler/heap-snapshot-generator.h"
       6             : 
       7             : #include <utility>
       8             : 
       9             : #include "src/api-inl.h"
      10             : #include "src/assembler-inl.h"
      11             : #include "src/conversions.h"
      12             : #include "src/debug/debug.h"
      13             : #include "src/global-handles.h"
      14             : #include "src/layout-descriptor.h"
      15             : #include "src/objects-body-descriptors.h"
      16             : #include "src/objects-inl.h"
      17             : #include "src/objects/allocation-site-inl.h"
      18             : #include "src/objects/api-callbacks.h"
      19             : #include "src/objects/cell-inl.h"
      20             : #include "src/objects/feedback-cell-inl.h"
      21             : #include "src/objects/hash-table-inl.h"
      22             : #include "src/objects/js-array-buffer-inl.h"
      23             : #include "src/objects/js-array-inl.h"
      24             : #include "src/objects/js-collection-inl.h"
      25             : #include "src/objects/js-generator-inl.h"
      26             : #include "src/objects/js-promise-inl.h"
      27             : #include "src/objects/js-regexp-inl.h"
      28             : #include "src/objects/literal-objects-inl.h"
      29             : #include "src/objects/slots-inl.h"
      30             : #include "src/objects/struct-inl.h"
      31             : #include "src/profiler/allocation-tracker.h"
      32             : #include "src/profiler/heap-profiler.h"
      33             : #include "src/profiler/heap-snapshot-generator-inl.h"
      34             : #include "src/prototype.h"
      35             : #include "src/transitions-inl.h"
      36             : #include "src/visitors.h"
      37             : 
      38             : namespace v8 {
      39             : namespace internal {
      40             : 
      41           0 : HeapGraphEdge::HeapGraphEdge(Type type, const char* name, HeapEntry* from,
      42             :                              HeapEntry* to)
      43     9725250 :     : bit_field_(TypeField::encode(type) |
      44             :                  FromIndexField::encode(from->index())),
      45             :       to_entry_(to),
      46     9725250 :       name_(name) {
      47             :   DCHECK(type == kContextVariable
      48             :       || type == kProperty
      49             :       || type == kInternal
      50             :       || type == kShortcut
      51             :       || type == kWeak);
      52           0 : }
      53             : 
      54           0 : HeapGraphEdge::HeapGraphEdge(Type type, int index, HeapEntry* from,
      55             :                              HeapEntry* to)
      56     1132049 :     : bit_field_(TypeField::encode(type) |
      57             :                  FromIndexField::encode(from->index())),
      58             :       to_entry_(to),
      59     1132049 :       index_(index) {
      60             :   DCHECK(type == kElement || type == kHidden);
      61           0 : }
      62             : 
      63           0 : HeapEntry::HeapEntry(HeapSnapshot* snapshot, int index, Type type,
      64             :                      const char* name, SnapshotObjectId id, size_t self_size,
      65             :                      unsigned trace_node_id)
      66             :     : type_(type),
      67             :       index_(index),
      68             :       children_count_(0),
      69             :       self_size_(self_size),
      70             :       snapshot_(snapshot),
      71             :       name_(name),
      72             :       id_(id),
      73     3078820 :       trace_node_id_(trace_node_id) {
      74             :   DCHECK_GE(index, 0);
      75           0 : }
      76             : 
      77           0 : void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
      78             :                                   const char* name,
      79             :                                   HeapEntry* entry) {
      80     9725250 :   ++children_count_;
      81     9725250 :   snapshot_->edges().emplace_back(type, name, this, entry);
      82           0 : }
      83             : 
      84           0 : void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
      85             :                                     int index,
      86             :                                     HeapEntry* entry) {
      87     1132049 :   ++children_count_;
      88     1132049 :   snapshot_->edges().emplace_back(type, index, this, entry);
      89           0 : }
      90             : 
      91     1208895 : void HeapEntry::SetNamedAutoIndexReference(HeapGraphEdge::Type type,
      92             :                                            const char* description,
      93             :                                            HeapEntry* child,
      94             :                                            StringsStorage* names) {
      95     1208895 :   int index = children_count_ + 1;
      96             :   const char* name = description
      97             :                          ? names->GetFormatted("%d / %s", index, description)
      98     1208895 :                          : names->GetName(index);
      99             :   SetNamedReference(type, name, child);
     100     1208895 : }
     101             : 
     102           0 : void HeapEntry::Print(
     103           0 :     const char* prefix, const char* edge_name, int max_depth, int indent) {
     104             :   STATIC_ASSERT(sizeof(unsigned) == sizeof(id()));
     105             :   base::OS::Print("%6" PRIuS " @%6u %*c %s%s: ", self_size(), id(), indent, ' ',
     106           0 :                   prefix, edge_name);
     107           0 :   if (type() != kString) {
     108           0 :     base::OS::Print("%s %.40s\n", TypeAsString(), name_);
     109             :   } else {
     110           0 :     base::OS::Print("\"");
     111           0 :     const char* c = name_;
     112           0 :     while (*c && (c - name_) <= 40) {
     113           0 :       if (*c != '\n')
     114           0 :         base::OS::Print("%c", *c);
     115             :       else
     116           0 :         base::OS::Print("\\n");
     117           0 :       ++c;
     118             :     }
     119           0 :     base::OS::Print("\"\n");
     120             :   }
     121           0 :   if (--max_depth == 0) return;
     122           0 :   for (auto i = children_begin(); i != children_end(); ++i) {
     123           0 :     HeapGraphEdge& edge = **i;
     124             :     const char* edge_prefix = "";
     125             :     EmbeddedVector<char, 64> index;
     126             :     const char* edge_name = index.start();
     127           0 :     switch (edge.type()) {
     128             :       case HeapGraphEdge::kContextVariable:
     129             :         edge_prefix = "#";
     130             :         edge_name = edge.name();
     131           0 :         break;
     132             :       case HeapGraphEdge::kElement:
     133           0 :         SNPrintF(index, "%d", edge.index());
     134           0 :         break;
     135             :       case HeapGraphEdge::kInternal:
     136             :         edge_prefix = "$";
     137             :         edge_name = edge.name();
     138           0 :         break;
     139             :       case HeapGraphEdge::kProperty:
     140             :         edge_name = edge.name();
     141           0 :         break;
     142             :       case HeapGraphEdge::kHidden:
     143             :         edge_prefix = "$";
     144           0 :         SNPrintF(index, "%d", edge.index());
     145           0 :         break;
     146             :       case HeapGraphEdge::kShortcut:
     147             :         edge_prefix = "^";
     148             :         edge_name = edge.name();
     149           0 :         break;
     150             :       case HeapGraphEdge::kWeak:
     151             :         edge_prefix = "w";
     152             :         edge_name = edge.name();
     153           0 :         break;
     154             :       default:
     155           0 :         SNPrintF(index, "!!! unknown edge type: %d ", edge.type());
     156             :     }
     157           0 :     edge.to()->Print(edge_prefix, edge_name, max_depth, indent + 2);
     158             :   }
     159             : }
     160             : 
     161           0 : const char* HeapEntry::TypeAsString() {
     162           0 :   switch (type()) {
     163             :     case kHidden: return "/hidden/";
     164           0 :     case kObject: return "/object/";
     165           0 :     case kClosure: return "/closure/";
     166           0 :     case kString: return "/string/";
     167           0 :     case kCode: return "/code/";
     168           0 :     case kArray: return "/array/";
     169           0 :     case kRegExp: return "/regexp/";
     170           0 :     case kHeapNumber: return "/number/";
     171           0 :     case kNative: return "/native/";
     172           0 :     case kSynthetic: return "/synthetic/";
     173           0 :     case kConsString: return "/concatenated string/";
     174           0 :     case kSlicedString: return "/sliced string/";
     175           0 :     case kSymbol: return "/symbol/";
     176             :     case kBigInt:
     177           0 :       return "/bigint/";
     178           0 :     default: return "???";
     179             :   }
     180             : }
     181             : 
     182        1194 : HeapSnapshot::HeapSnapshot(HeapProfiler* profiler) : profiler_(profiler) {
     183             :   // It is very important to keep objects that form a heap snapshot
     184             :   // as small as possible. Check assumptions about data structure sizes.
     185             :   STATIC_ASSERT((kTaggedSize == 4 && sizeof(HeapGraphEdge) == 12) ||
     186             :                 (kTaggedSize == 8 && sizeof(HeapGraphEdge) == 24));
     187             :   STATIC_ASSERT((kTaggedSize == 4 && sizeof(HeapEntry) == 28) ||
     188             :                 (kTaggedSize == 8 && sizeof(HeapEntry) == 40));
     189         398 :   memset(&gc_subroot_entries_, 0, sizeof(gc_subroot_entries_));
     190         398 : }
     191             : 
     192           5 : void HeapSnapshot::Delete() {
     193           5 :   profiler_->RemoveSnapshot(this);
     194           5 : }
     195             : 
     196           0 : void HeapSnapshot::RememberLastJSObjectId() {
     197        1179 :   max_snapshot_js_object_id_ = profiler_->heap_object_map()->last_assigned_id();
     198           0 : }
     199             : 
     200         398 : void HeapSnapshot::AddSyntheticRootEntries() {
     201         398 :   AddRootEntry();
     202         398 :   AddGcRootsEntry();
     203             :   SnapshotObjectId id = HeapObjectsMap::kGcRootsFirstSubrootId;
     204        9950 :   for (int root = 0; root < static_cast<int>(Root::kNumberOfRoots); root++) {
     205        9552 :     AddGcSubrootEntry(static_cast<Root>(root), id);
     206        9552 :     id += HeapObjectsMap::kObjectIdStep;
     207             :   }
     208             :   DCHECK_EQ(HeapObjectsMap::kFirstAvailableObjectId, id);
     209         398 : }
     210             : 
     211         398 : void HeapSnapshot::AddRootEntry() {
     212             :   DCHECK_NULL(root_entry_);
     213             :   DCHECK(entries_.empty());  // Root entry must be the first one.
     214             :   root_entry_ = AddEntry(HeapEntry::kSynthetic, "",
     215         398 :                          HeapObjectsMap::kInternalRootObjectId, 0, 0);
     216             :   DCHECK_EQ(1u, entries_.size());
     217             :   DCHECK_EQ(root_entry_, &entries_.front());
     218         398 : }
     219             : 
     220         398 : void HeapSnapshot::AddGcRootsEntry() {
     221             :   DCHECK_NULL(gc_roots_entry_);
     222             :   gc_roots_entry_ = AddEntry(HeapEntry::kSynthetic, "(GC roots)",
     223         398 :                              HeapObjectsMap::kGcRootsObjectId, 0, 0);
     224         398 : }
     225             : 
     226        9552 : void HeapSnapshot::AddGcSubrootEntry(Root root, SnapshotObjectId id) {
     227             :   DCHECK_NULL(gc_subroot_entries_[static_cast<int>(root)]);
     228             :   gc_subroot_entries_[static_cast<int>(root)] =
     229        9552 :       AddEntry(HeapEntry::kSynthetic, RootVisitor::RootName(root), id, 0, 0);
     230        9552 : }
     231             : 
     232           0 : void HeapSnapshot::AddLocation(HeapEntry* entry, int scriptId, int line,
     233             :                                int col) {
     234      134691 :   locations_.emplace_back(entry->index(), scriptId, line, col);
     235           0 : }
     236             : 
     237     3078820 : HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
     238             :                                   const char* name,
     239             :                                   SnapshotObjectId id,
     240             :                                   size_t size,
     241             :                                   unsigned trace_node_id) {
     242             :   DCHECK(!is_complete());
     243             :   entries_.emplace_back(this, static_cast<int>(entries_.size()), type, name, id,
     244     3078820 :                         size, trace_node_id);
     245     3078820 :   return &entries_.back();
     246             : }
     247             : 
     248         393 : void HeapSnapshot::FillChildren() {
     249             :   DCHECK(children().empty());
     250             :   int children_index = 0;
     251     3063778 :   for (HeapEntry& entry : entries()) {
     252             :     children_index = entry.set_children_index(children_index);
     253             :   }
     254             :   DCHECK_EQ(edges().size(), static_cast<size_t>(children_index));
     255         393 :   children().resize(edges().size());
     256    10839482 :   for (HeapGraphEdge& edge : edges()) {
     257    10839089 :     edge.from()->add_child(&edge);
     258             :   }
     259         393 : }
     260             : 
     261      182484 : HeapEntry* HeapSnapshot::GetEntryById(SnapshotObjectId id) {
     262      182484 :   if (entries_by_id_cache_.empty()) {
     263          10 :     CHECK(is_complete());
     264             :     entries_by_id_cache_.reserve(entries_.size());
     265      133236 :     for (HeapEntry& entry : entries_) {
     266      199839 :       entries_by_id_cache_.emplace(entry.id(), &entry);
     267             :     }
     268             :   }
     269             :   auto it = entries_by_id_cache_.find(id);
     270      182484 :   return it != entries_by_id_cache_.end() ? it->second : nullptr;
     271             : }
     272             : 
     273           0 : void HeapSnapshot::Print(int max_depth) {
     274           0 :   root()->Print("", "", max_depth, 0);
     275           0 : }
     276             : 
     277             : // We split IDs on evens for embedder objects (see
     278             : // HeapObjectsMap::GenerateId) and odds for native objects.
     279             : const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = 1;
     280             : const SnapshotObjectId HeapObjectsMap::kGcRootsObjectId =
     281             :     HeapObjectsMap::kInternalRootObjectId + HeapObjectsMap::kObjectIdStep;
     282             : const SnapshotObjectId HeapObjectsMap::kGcRootsFirstSubrootId =
     283             :     HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep;
     284             : const SnapshotObjectId HeapObjectsMap::kFirstAvailableObjectId =
     285             :     HeapObjectsMap::kGcRootsFirstSubrootId +
     286             :     static_cast<int>(Root::kNumberOfRoots) * HeapObjectsMap::kObjectIdStep;
     287             : 
     288       64885 : HeapObjectsMap::HeapObjectsMap(Heap* heap)
     289      129771 :     : next_id_(kFirstAvailableObjectId), heap_(heap) {
     290             :   // The dummy element at zero index is needed as entries_map_ cannot hold
     291             :   // an entry with zero value. Otherwise it's impossible to tell if
     292             :   // LookupOrInsert has added a new item or just returning exisiting one
     293             :   // having the value of zero.
     294       64886 :   entries_.emplace_back(0, kNullAddress, 0, true);
     295       64885 : }
     296             : 
     297      173529 : bool HeapObjectsMap::MoveObject(Address from, Address to, int object_size) {
     298             :   DCHECK_NE(kNullAddress, to);
     299             :   DCHECK_NE(kNullAddress, from);
     300      173529 :   if (from == to) return false;
     301             :   void* from_value = entries_map_.Remove(reinterpret_cast<void*>(from),
     302      173529 :                                          ComputeAddressHash(from));
     303      173529 :   if (from_value == nullptr) {
     304             :     // It may occur that some untracked object moves to an address X and there
     305             :     // is a tracked object at that address. In this case we should remove the
     306             :     // entry as we know that the object has died.
     307             :     void* to_value = entries_map_.Remove(reinterpret_cast<void*>(to),
     308      171972 :                                          ComputeAddressHash(to));
     309      171972 :     if (to_value != nullptr) {
     310             :       int to_entry_info_index =
     311           0 :           static_cast<int>(reinterpret_cast<intptr_t>(to_value));
     312           0 :       entries_.at(to_entry_info_index).addr = kNullAddress;
     313             :     }
     314             :   } else {
     315             :     base::HashMap::Entry* to_entry = entries_map_.LookupOrInsert(
     316        3114 :         reinterpret_cast<void*>(to), ComputeAddressHash(to));
     317        1557 :     if (to_entry->value != nullptr) {
     318             :       // We found the existing entry with to address for an old object.
     319             :       // Without this operation we will have two EntryInfo's with the same
     320             :       // value in addr field. It is bad because later at RemoveDeadEntries
     321             :       // one of this entry will be removed with the corresponding entries_map_
     322             :       // entry.
     323             :       int to_entry_info_index =
     324           0 :           static_cast<int>(reinterpret_cast<intptr_t>(to_entry->value));
     325           0 :       entries_.at(to_entry_info_index).addr = kNullAddress;
     326             :     }
     327             :     int from_entry_info_index =
     328        1557 :         static_cast<int>(reinterpret_cast<intptr_t>(from_value));
     329        3114 :     entries_.at(from_entry_info_index).addr = to;
     330             :     // Size of an object can change during its life, so to keep information
     331             :     // about the object in entries_ consistent, we have to adjust size when the
     332             :     // object is migrated.
     333        1557 :     if (FLAG_heap_profiler_trace_objects) {
     334             :       PrintF("Move object from %p to %p old size %6d new size %6d\n",
     335             :              reinterpret_cast<void*>(from), reinterpret_cast<void*>(to),
     336           0 :              entries_.at(from_entry_info_index).size, object_size);
     337             :     }
     338        1557 :     entries_.at(from_entry_info_index).size = object_size;
     339        1557 :     to_entry->value = from_value;
     340             :   }
     341      173529 :   return from_value != nullptr;
     342             : }
     343             : 
     344             : 
     345           0 : void HeapObjectsMap::UpdateObjectSize(Address addr, int size) {
     346           0 :   FindOrAddEntry(addr, size, false);
     347           0 : }
     348             : 
     349             : 
     350      907523 : SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) {
     351             :   base::HashMap::Entry* entry = entries_map_.Lookup(
     352      907523 :       reinterpret_cast<void*>(addr), ComputeAddressHash(addr));
     353      907523 :   if (entry == nullptr) return 0;
     354      583841 :   int entry_index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
     355      583841 :   EntryInfo& entry_info = entries_.at(entry_index);
     356             :   DCHECK(static_cast<uint32_t>(entries_.size()) > entries_map_.occupancy());
     357      583841 :   return entry_info.id;
     358             : }
     359             : 
     360             : 
     361     3850270 : SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr,
     362             :                                                 unsigned int size,
     363             :                                                 bool accessed) {
     364             :   DCHECK(static_cast<uint32_t>(entries_.size()) > entries_map_.occupancy());
     365             :   base::HashMap::Entry* entry = entries_map_.LookupOrInsert(
     366     7700540 :       reinterpret_cast<void*>(addr), ComputeAddressHash(addr));
     367     3850270 :   if (entry->value != nullptr) {
     368             :     int entry_index =
     369      965553 :         static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
     370     3850270 :     EntryInfo& entry_info = entries_.at(entry_index);
     371      965553 :     entry_info.accessed = accessed;
     372      965553 :     if (FLAG_heap_profiler_trace_objects) {
     373             :       PrintF("Update object size : %p with old size %d and new size %d\n",
     374           0 :              reinterpret_cast<void*>(addr), entry_info.size, size);
     375             :     }
     376      965553 :     entry_info.size = size;
     377      965553 :     return entry_info.id;
     378             :   }
     379     2884717 :   entry->value = reinterpret_cast<void*>(entries_.size());
     380     2884717 :   SnapshotObjectId id = next_id_;
     381     2884717 :   next_id_ += kObjectIdStep;
     382     5769434 :   entries_.push_back(EntryInfo(id, addr, size, accessed));
     383             :   DCHECK(static_cast<uint32_t>(entries_.size()) > entries_map_.occupancy());
     384     2884717 :   return id;
     385             : }
     386             : 
     387        7754 : void HeapObjectsMap::StopHeapObjectsTracking() { time_intervals_.clear(); }
     388             : 
     389         100 : void HeapObjectsMap::UpdateHeapObjectsMap() {
     390         100 :   if (FLAG_heap_profiler_trace_objects) {
     391             :     PrintF("Begin HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n",
     392           0 :            entries_map_.occupancy());
     393             :   }
     394             :   heap_->PreciseCollectAllGarbage(Heap::kNoGCFlags,
     395         100 :                                   GarbageCollectionReason::kHeapProfiler);
     396         100 :   HeapIterator iterator(heap_);
     397     1326650 :   for (HeapObject obj = iterator.next(); !obj.is_null();
     398             :        obj = iterator.next()) {
     399     1326450 :     FindOrAddEntry(obj->address(), obj->Size());
     400      663225 :     if (FLAG_heap_profiler_trace_objects) {
     401             :       PrintF("Update object      : %p %6d. Next address is %p\n",
     402             :              reinterpret_cast<void*>(obj->address()), obj->Size(),
     403           0 :              reinterpret_cast<void*>(obj->address() + obj->Size()));
     404             :     }
     405             :   }
     406         100 :   RemoveDeadEntries();
     407         100 :   if (FLAG_heap_profiler_trace_objects) {
     408             :     PrintF("End HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n",
     409           0 :            entries_map_.occupancy());
     410         100 :   }
     411         100 : }
     412             : 
     413          55 : SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream,
     414          55 :                                                       int64_t* timestamp_us) {
     415          55 :   UpdateHeapObjectsMap();
     416         390 :   time_intervals_.emplace_back(next_id_);
     417          55 :   int prefered_chunk_size = stream->GetChunkSize();
     418             :   std::vector<v8::HeapStatsUpdate> stats_buffer;
     419             :   DCHECK(!entries_.empty());
     420             :   EntryInfo* entry_info = &entries_.front();
     421             :   EntryInfo* end_entry_info = &entries_.back() + 1;
     422         670 :   for (size_t time_interval_index = 0;
     423             :        time_interval_index < time_intervals_.size(); ++time_interval_index) {
     424             :     TimeInterval& time_interval = time_intervals_[time_interval_index];
     425         280 :     SnapshotObjectId time_interval_id = time_interval.id;
     426             :     uint32_t entries_size = 0;
     427             :     EntryInfo* start_entry_info = entry_info;
     428      364918 :     while (entry_info < end_entry_info && entry_info->id < time_interval_id) {
     429      364358 :       entries_size += entry_info->size;
     430      364358 :       ++entry_info;
     431             :     }
     432             :     uint32_t entries_count =
     433         280 :         static_cast<uint32_t>(entry_info - start_entry_info);
     434         510 :     if (time_interval.count != entries_count ||
     435         230 :         time_interval.size != entries_size) {
     436             :       stats_buffer.emplace_back(static_cast<uint32_t>(time_interval_index),
     437             :                                 time_interval.count = entries_count,
     438          50 :                                 time_interval.size = entries_size);
     439         100 :       if (static_cast<int>(stats_buffer.size()) >= prefered_chunk_size) {
     440             :         OutputStream::WriteResult result = stream->WriteHeapStatsChunk(
     441           0 :             &stats_buffer.front(), static_cast<int>(stats_buffer.size()));
     442           0 :         if (result == OutputStream::kAbort) return last_assigned_id();
     443             :         stats_buffer.clear();
     444             :       }
     445             :     }
     446             :   }
     447             :   DCHECK(entry_info == end_entry_info);
     448          55 :   if (!stats_buffer.empty()) {
     449             :     OutputStream::WriteResult result = stream->WriteHeapStatsChunk(
     450          90 :         &stats_buffer.front(), static_cast<int>(stats_buffer.size()));
     451          45 :     if (result == OutputStream::kAbort) return last_assigned_id();
     452             :   }
     453          55 :   stream->EndOfStream();
     454          55 :   if (timestamp_us) {
     455             :     *timestamp_us =
     456         110 :         (time_intervals_.back().timestamp - time_intervals_.front().timestamp)
     457          55 :             .InMicroseconds();
     458             :   }
     459          55 :   return last_assigned_id();
     460             : }
     461             : 
     462             : 
     463         498 : void HeapObjectsMap::RemoveDeadEntries() {
     464             :   DCHECK(entries_.size() > 0 && entries_.at(0).id == 0 &&
     465             :          entries_.at(0).addr == kNullAddress);
     466             :   size_t first_free_entry = 1;
     467     7564468 :   for (size_t i = 1; i < entries_.size(); ++i) {
     468     3782234 :     EntryInfo& entry_info = entries_.at(i);
     469     3781736 :     if (entry_info.accessed) {
     470     3731617 :       if (first_free_entry != i) {
     471       80584 :         entries_.at(first_free_entry) = entry_info;
     472             :       }
     473     3731617 :       entries_.at(first_free_entry).accessed = false;
     474             :       base::HashMap::Entry* entry =
     475             :           entries_map_.Lookup(reinterpret_cast<void*>(entry_info.addr),
     476     7463234 :                               ComputeAddressHash(entry_info.addr));
     477             :       DCHECK(entry);
     478     3731617 :       entry->value = reinterpret_cast<void*>(first_free_entry);
     479     3731617 :       ++first_free_entry;
     480             :     } else {
     481       50119 :       if (entry_info.addr) {
     482             :         entries_map_.Remove(reinterpret_cast<void*>(entry_info.addr),
     483       50119 :                             ComputeAddressHash(entry_info.addr));
     484             :       }
     485             :     }
     486             :   }
     487         498 :   entries_.erase(entries_.begin() + first_free_entry, entries_.end());
     488             : 
     489             :   DCHECK(static_cast<uint32_t>(entries_.size()) - 1 ==
     490             :          entries_map_.occupancy());
     491         498 : }
     492             : 
     493         796 : V8HeapExplorer::V8HeapExplorer(HeapSnapshot* snapshot,
     494             :                                SnapshottingProgressReportingInterface* progress,
     495             :                                v8::HeapProfiler::ObjectNameResolver* resolver)
     496         398 :     : heap_(snapshot->profiler()->heap_object_map()->heap()),
     497             :       snapshot_(snapshot),
     498         796 :       names_(snapshot_->profiler()->names()),
     499             :       heap_object_map_(snapshot_->profiler()->heap_object_map()),
     500             :       progress_(progress),
     501             :       generator_(nullptr),
     502        3184 :       global_object_name_resolver_(resolver) {}
     503             : 
     504     3068382 : HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) {
     505     6136764 :   return AddEntry(HeapObject::cast(Object(reinterpret_cast<Address>(ptr))));
     506             : }
     507             : 
     508     2991792 : void V8HeapExplorer::ExtractLocation(HeapEntry* entry, HeapObject object) {
     509     2991792 :   if (object->IsJSFunction()) {
     510      277022 :     JSFunction func = JSFunction::cast(object);
     511      277022 :     ExtractLocationForJSFunction(entry, func);
     512             : 
     513     2714770 :   } else if (object->IsJSGeneratorObject()) {
     514          10 :     JSGeneratorObject gen = JSGeneratorObject::cast(object);
     515          10 :     ExtractLocationForJSFunction(entry, gen->function());
     516             : 
     517     2714760 :   } else if (object->IsJSObject()) {
     518      141424 :     JSObject obj = JSObject::cast(object);
     519      141424 :     JSFunction maybe_constructor = GetConstructor(obj);
     520             : 
     521      141424 :     if (!maybe_constructor.is_null()) {
     522      109318 :       ExtractLocationForJSFunction(entry, maybe_constructor);
     523             :     }
     524             :   }
     525     2991792 : }
     526             : 
     527      386350 : void V8HeapExplorer::ExtractLocationForJSFunction(HeapEntry* entry,
     528             :                                                   JSFunction func) {
     529     1024359 :   if (!func->shared()->script()->IsScript()) return;
     530      269382 :   Script script = Script::cast(func->shared()->script());
     531             :   int scriptId = script->id();
     532      134691 :   int start = func->shared()->StartPosition();
     533      134691 :   int line = script->GetLineNumber(start);
     534      134691 :   int col = script->GetColumnNumber(start);
     535      134691 :   snapshot_->AddLocation(entry, scriptId, line, col);
     536             : }
     537             : 
     538     3068382 : HeapEntry* V8HeapExplorer::AddEntry(HeapObject object) {
     539     3068382 :   if (object->IsJSFunction()) {
     540      277022 :     JSFunction func = JSFunction::cast(object);
     541      277022 :     SharedFunctionInfo shared = func->shared();
     542      277022 :     const char* name = names_->GetName(shared->Name());
     543      277022 :     return AddEntry(object, HeapEntry::kClosure, name);
     544     2791360 :   } else if (object->IsJSBoundFunction()) {
     545         398 :     return AddEntry(object, HeapEntry::kClosure, "native_bind");
     546     2790962 :   } else if (object->IsJSRegExp()) {
     547           0 :     JSRegExp re = JSRegExp::cast(object);
     548             :     return AddEntry(object,
     549             :                     HeapEntry::kRegExp,
     550           0 :                     names_->GetName(re->Pattern()));
     551     2790962 :   } else if (object->IsJSObject()) {
     552             :     const char* name = names_->GetName(
     553      141041 :         GetConstructorName(JSObject::cast(object)));
     554      141041 :     if (object->IsJSGlobalObject()) {
     555         796 :       auto it = objects_tags_.find(JSGlobalObject::cast(object));
     556         398 :       if (it != objects_tags_.end()) {
     557          30 :         name = names_->GetFormatted("%s / %s", name, it->second);
     558             :       }
     559             :     }
     560      141041 :     return AddEntry(object, HeapEntry::kObject, name);
     561     2649921 :   } else if (object->IsString()) {
     562      602644 :     String string = String::cast(object);
     563      602644 :     if (string->IsConsString()) {
     564      120020 :       return AddEntry(object, HeapEntry::kConsString, "(concatenated string)");
     565      482624 :     } else if (string->IsSlicedString()) {
     566           5 :       return AddEntry(object, HeapEntry::kSlicedString, "(sliced string)");
     567             :     } else {
     568             :       return AddEntry(object, HeapEntry::kString,
     569      482619 :                       names_->GetName(String::cast(object)));
     570             :     }
     571     2047277 :   } else if (object->IsSymbol()) {
     572       17149 :     if (Symbol::cast(object)->is_private())
     573       11572 :       return AddEntry(object, HeapEntry::kHidden, "private symbol");
     574             :     else
     575        5577 :       return AddEntry(object, HeapEntry::kSymbol, "symbol");
     576     2030128 :   } else if (object->IsBigInt()) {
     577          10 :     return AddEntry(object, HeapEntry::kBigInt, "bigint");
     578     2030118 :   } else if (object->IsCode()) {
     579      600459 :     return AddEntry(object, HeapEntry::kCode, "");
     580     1429659 :   } else if (object->IsSharedFunctionInfo()) {
     581      287947 :     String name = SharedFunctionInfo::cast(object)->Name();
     582      287947 :     return AddEntry(object, HeapEntry::kCode, names_->GetName(name));
     583     1141712 :   } else if (object->IsScript()) {
     584        1492 :     Object name = Script::cast(object)->name();
     585             :     return AddEntry(
     586             :         object, HeapEntry::kCode,
     587        1935 :         name->IsString() ? names_->GetName(String::cast(name)) : "");
     588     1140220 :   } else if (object->IsNativeContext()) {
     589         398 :     return AddEntry(object, HeapEntry::kHidden, "system / NativeContext");
     590     1139822 :   } else if (object->IsContext()) {
     591        2040 :     return AddEntry(object, HeapEntry::kObject, "system / Context");
     592     3389541 :   } else if (object->IsFixedArray() || object->IsFixedDoubleArray() ||
     593             :              object->IsByteArray()) {
     594       16216 :     return AddEntry(object, HeapEntry::kArray, "");
     595     1121566 :   } else if (object->IsHeapNumber()) {
     596       14187 :     return AddEntry(object, HeapEntry::kHeapNumber, "number");
     597             :   }
     598     1107379 :   return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object));
     599             : }
     600             : 
     601     3068382 : HeapEntry* V8HeapExplorer::AddEntry(HeapObject object, HeapEntry::Type type,
     602             :                                     const char* name) {
     603     6136764 :   return AddEntry(object->address(), type, name, object->Size());
     604             : }
     605             : 
     606     3068392 : HeapEntry* V8HeapExplorer::AddEntry(Address address,
     607             :                                     HeapEntry::Type type,
     608             :                                     const char* name,
     609             :                                     size_t size) {
     610             :   SnapshotObjectId object_id = heap_object_map_->FindOrAddEntry(
     611     3068392 :       address, static_cast<unsigned int>(size));
     612             :   unsigned trace_node_id = 0;
     613     3068392 :   if (AllocationTracker* allocation_tracker =
     614     3068392 :       snapshot_->profiler()->allocation_tracker()) {
     615             :     trace_node_id =
     616       33108 :         allocation_tracker->address_to_trace()->GetTraceNodeId(address);
     617             :   }
     618     3068392 :   return snapshot_->AddEntry(type, name, object_id, size, trace_node_id);
     619             : }
     620             : 
     621     1107379 : const char* V8HeapExplorer::GetSystemEntryName(HeapObject object) {
     622     1107379 :   switch (object->map()->instance_type()) {
     623             :     case MAP_TYPE:
     624      177460 :       switch (Map::cast(object)->instance_type()) {
     625             : #define MAKE_STRING_MAP_CASE(instance_type, size, name, Name) \
     626             :         case instance_type: return "system / Map (" #Name ")";
     627         398 :       STRING_TYPE_LIST(MAKE_STRING_MAP_CASE)
     628             : #undef MAKE_STRING_MAP_CASE
     629      168306 :         default: return "system / Map";
     630             :       }
     631             :     case CELL_TYPE: return "system / Cell";
     632       28896 :     case PROPERTY_CELL_TYPE: return "system / PropertyCell";
     633       27351 :     case FOREIGN_TYPE: return "system / Foreign";
     634        4776 :     case ODDBALL_TYPE: return "system / Oddball";
     635             :     case ALLOCATION_SITE_TYPE:
     636          16 :       return "system / AllocationSite";
     637             : #define MAKE_STRUCT_CASE(TYPE, Name, name) \
     638             :   case TYPE:                               \
     639             :     return "system / " #Name;
     640          10 :       STRUCT_LIST(MAKE_STRUCT_CASE)
     641             : #undef MAKE_STRUCT_CASE
     642      801919 :     default: return "system";
     643             :   }
     644             : }
     645             : 
     646          15 : int V8HeapExplorer::EstimateObjectsCount() {
     647          15 :   HeapIterator it(heap_, HeapIterator::kFilterUnreachable);
     648             :   int objects_count = 0;
     649       96942 :   while (!it.next().is_null()) ++objects_count;
     650          15 :   return objects_count;
     651             : }
     652             : 
     653     2991792 : class IndexedReferencesExtractor : public ObjectVisitor {
     654             :  public:
     655     2991792 :   IndexedReferencesExtractor(V8HeapExplorer* generator, HeapObject parent_obj,
     656             :                              HeapEntry* parent)
     657             :       : generator_(generator),
     658             :         parent_obj_(parent_obj),
     659             :         parent_start_(HeapObject::RawMaybeWeakField(parent_obj_, 0)),
     660             :         parent_end_(
     661     2991792 :             HeapObject::RawMaybeWeakField(parent_obj_, parent_obj_->Size())),
     662             :         parent_(parent),
     663     8975376 :         next_index_(0) {}
     664     6404573 :   void VisitPointers(HeapObject host, ObjectSlot start,
     665             :                      ObjectSlot end) override {
     666    12809146 :     VisitPointers(host, MaybeObjectSlot(start), MaybeObjectSlot(end));
     667     6404573 :   }
     668     6652111 :   void VisitPointers(HeapObject host, MaybeObjectSlot start,
     669             :                      MaybeObjectSlot end) override {
     670             :     // [start,end) must be a sub-region of [parent_start_, parent_end), i.e.
     671             :     // all the slots must point inside the object.
     672     6652111 :     CHECK_LE(parent_start_, start);
     673     6652111 :     CHECK_LE(end, parent_end_);
     674    29269885 :     for (MaybeObjectSlot p = start; p < end; ++p) {
     675    15965663 :       int field_index = static_cast<int>(p - parent_start_);
     676    31931326 :       if (generator_->visited_fields_[field_index]) {
     677             :         generator_->visited_fields_[field_index] = false;
     678    12389151 :         continue;
     679             :       }
     680     3576512 :       HeapObject heap_object;
     681     3576512 :       if ((*p)->GetHeapObject(&heap_object)) {
     682             :         VisitHeapObjectImpl(heap_object, field_index);
     683             :       }
     684             :     }
     685     6652111 :   }
     686             : 
     687        2751 :   void VisitCodeTarget(Code host, RelocInfo* rinfo) override {
     688        2751 :     Code target = Code::GetCodeFromTargetAddress(rinfo->target_address());
     689             :     VisitHeapObjectImpl(target, -1);
     690        2751 :   }
     691             : 
     692        1032 :   void VisitEmbeddedPointer(Code host, RelocInfo* rinfo) override {
     693             :     VisitHeapObjectImpl(rinfo->target_object(), -1);
     694        1032 :   }
     695             : 
     696             :  private:
     697             :   V8_INLINE void VisitHeapObjectImpl(HeapObject heap_object, int field_index) {
     698             :     DCHECK_LE(-1, field_index);
     699             :     // The last parameter {field_offset} is only used to check some well-known
     700             :     // skipped references, so passing -1 * kTaggedSize for objects embedded
     701             :     // into code is fine.
     702             :     generator_->SetHiddenReference(parent_obj_, parent_, next_index_++,
     703     1891493 :                                    heap_object, field_index * kTaggedSize);
     704             :   }
     705             : 
     706             :   V8HeapExplorer* generator_;
     707             :   HeapObject parent_obj_;
     708             :   MaybeObjectSlot parent_start_;
     709             :   MaybeObjectSlot parent_end_;
     710             :   HeapEntry* parent_;
     711             :   int next_index_;
     712             : };
     713             : 
     714     2991792 : void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject obj) {
     715     2991792 :   if (obj->IsJSGlobalProxy()) {
     716             :     ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
     717     2991399 :   } else if (obj->IsJSArrayBuffer()) {
     718          15 :     ExtractJSArrayBufferReferences(entry, JSArrayBuffer::cast(obj));
     719     2991384 :   } else if (obj->IsJSObject()) {
     720      418048 :     if (obj->IsJSWeakSet()) {
     721             :       ExtractJSWeakCollectionReferences(entry, JSWeakSet::cast(obj));
     722      418043 :     } else if (obj->IsJSWeakMap()) {
     723             :       ExtractJSWeakCollectionReferences(entry, JSWeakMap::cast(obj));
     724      418033 :     } else if (obj->IsJSSet()) {
     725             :       ExtractJSCollectionReferences(entry, JSSet::cast(obj));
     726      418028 :     } else if (obj->IsJSMap()) {
     727             :       ExtractJSCollectionReferences(entry, JSMap::cast(obj));
     728      418023 :     } else if (obj->IsJSPromise()) {
     729             :       ExtractJSPromiseReferences(entry, JSPromise::cast(obj));
     730      417998 :     } else if (obj->IsJSGeneratorObject()) {
     731          10 :       ExtractJSGeneratorObjectReferences(entry, JSGeneratorObject::cast(obj));
     732             :     }
     733      418048 :     ExtractJSObjectReferences(entry, JSObject::cast(obj));
     734     2573336 :   } else if (obj->IsString()) {
     735      599439 :     ExtractStringReferences(entry, String::cast(obj));
     736     1973897 :   } else if (obj->IsSymbol()) {
     737             :     ExtractSymbolReferences(entry, Symbol::cast(obj));
     738     1967295 :   } else if (obj->IsMap()) {
     739      136650 :     ExtractMapReferences(entry, Map::cast(obj));
     740     1830645 :   } else if (obj->IsSharedFunctionInfo()) {
     741      284842 :     ExtractSharedFunctionInfoReferences(entry, SharedFunctionInfo::cast(obj));
     742     1545803 :   } else if (obj->IsScript()) {
     743        1487 :     ExtractScriptReferences(entry, Script::cast(obj));
     744     1544316 :   } else if (obj->IsAccessorInfo()) {
     745        4323 :     ExtractAccessorInfoReferences(entry, AccessorInfo::cast(obj));
     746     1539993 :   } else if (obj->IsAccessorPair()) {
     747       24501 :     ExtractAccessorPairReferences(entry, AccessorPair::cast(obj));
     748     1515492 :   } else if (obj->IsCode()) {
     749      592929 :     ExtractCodeReferences(entry, Code::cast(obj));
     750      922563 :   } else if (obj->IsCell()) {
     751             :     ExtractCellReferences(entry, Cell::cast(obj));
     752      919498 :   } else if (obj->IsFeedbackCell()) {
     753       34874 :     ExtractFeedbackCellReferences(entry, FeedbackCell::cast(obj));
     754      884624 :   } else if (obj->IsPropertyCell()) {
     755       28438 :     ExtractPropertyCellReferences(entry, PropertyCell::cast(obj));
     756      856186 :   } else if (obj->IsAllocationSite()) {
     757          16 :     ExtractAllocationSiteReferences(entry, AllocationSite::cast(obj));
     758      856170 :   } else if (obj->IsArrayBoilerplateDescription()) {
     759             :     ExtractArrayBoilerplateDescriptionReferences(
     760          25 :         entry, ArrayBoilerplateDescription::cast(obj));
     761      856145 :   } else if (obj->IsFeedbackVector()) {
     762         448 :     ExtractFeedbackVectorReferences(entry, FeedbackVector::cast(obj));
     763      855697 :   } else if (obj->IsDescriptorArray()) {
     764       79991 :     ExtractDescriptorArrayReferences(entry, DescriptorArray::cast(obj));
     765      775706 :   } else if (obj->IsWeakFixedArray()) {
     766             :     ExtractWeakArrayReferences(WeakFixedArray::kHeaderSize, entry,
     767        5096 :                                WeakFixedArray::cast(obj));
     768      770610 :   } else if (obj->IsWeakArrayList()) {
     769             :     ExtractWeakArrayReferences(WeakArrayList::kHeaderSize, entry,
     770        1514 :                                WeakArrayList::cast(obj));
     771      769096 :   } else if (obj->IsContext()) {
     772        2433 :     ExtractContextReferences(entry, Context::cast(obj));
     773      766663 :   } else if (obj->IsEphemeronHashTable()) {
     774          15 :     ExtractEphemeronHashTableReferences(entry, EphemeronHashTable::cast(obj));
     775      766648 :   } else if (obj->IsFixedArray()) {
     776       10029 :     ExtractFixedArrayReferences(entry, FixedArray::cast(obj));
     777             :   }
     778     2991792 : }
     779             : 
     780           0 : void V8HeapExplorer::ExtractJSGlobalProxyReferences(HeapEntry* entry,
     781             :                                                     JSGlobalProxy proxy) {
     782             :   SetInternalReference(entry, "native_context", proxy->native_context(),
     783         393 :                        JSGlobalProxy::kNativeContextOffset);
     784           0 : }
     785             : 
     786      418048 : void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry,
     787             :                                                JSObject js_obj) {
     788      418048 :   HeapObject obj = js_obj;
     789      418048 :   ExtractPropertyReferences(js_obj, entry);
     790      418048 :   ExtractElementReferences(js_obj, entry);
     791      418048 :   ExtractInternalReferences(js_obj, entry);
     792      418048 :   Isolate* isolate = Isolate::FromHeap(heap_);
     793             :   PrototypeIterator iter(isolate, js_obj);
     794             :   ReadOnlyRoots roots(isolate);
     795      418048 :   SetPropertyReference(entry, roots.proto_string(), iter.GetCurrent());
     796      418048 :   if (obj->IsJSBoundFunction()) {
     797         398 :     JSBoundFunction js_fun = JSBoundFunction::cast(obj);
     798         398 :     TagObject(js_fun->bound_arguments(), "(bound arguments)");
     799             :     SetInternalReference(entry, "bindings", js_fun->bound_arguments(),
     800         398 :                          JSBoundFunction::kBoundArgumentsOffset);
     801             :     SetInternalReference(entry, "bound_this", js_fun->bound_this(),
     802         398 :                          JSBoundFunction::kBoundThisOffset);
     803             :     SetInternalReference(entry, "bound_function",
     804             :                          js_fun->bound_target_function(),
     805         398 :                          JSBoundFunction::kBoundTargetFunctionOffset);
     806         398 :     FixedArray bindings = js_fun->bound_arguments();
     807         816 :     for (int i = 0; i < bindings->length(); i++) {
     808          10 :       const char* reference_name = names_->GetFormatted("bound_argument_%d", i);
     809          10 :       SetNativeBindReference(entry, reference_name, bindings->get(i));
     810             :     }
     811      417650 :   } else if (obj->IsJSFunction()) {
     812      277022 :     JSFunction js_fun = JSFunction::cast(js_obj);
     813      277022 :     if (js_fun->has_prototype_slot()) {
     814       68289 :       Object proto_or_map = js_fun->prototype_or_initial_map();
     815       68289 :       if (!proto_or_map->IsTheHole(isolate)) {
     816       34381 :         if (!proto_or_map->IsMap()) {
     817             :           SetPropertyReference(entry, roots.prototype_string(), proto_or_map,
     818             :                                nullptr,
     819           5 :                                JSFunction::kPrototypeOrInitialMapOffset);
     820             :         } else {
     821             :           SetPropertyReference(entry, roots.prototype_string(),
     822       68752 :                                js_fun->prototype());
     823             :           SetInternalReference(entry, "initial_map", proto_or_map,
     824       34376 :                                JSFunction::kPrototypeOrInitialMapOffset);
     825             :         }
     826             :       }
     827             :     }
     828      277022 :     SharedFunctionInfo shared_info = js_fun->shared();
     829      277022 :     TagObject(js_fun->raw_feedback_cell(), "(function feedback cell)");
     830             :     SetInternalReference(entry, "feedback_cell", js_fun->raw_feedback_cell(),
     831      277022 :                          JSFunction::kFeedbackCellOffset);
     832      277022 :     TagObject(shared_info, "(shared function info)");
     833             :     SetInternalReference(entry, "shared", shared_info,
     834      277022 :                          JSFunction::kSharedFunctionInfoOffset);
     835      277022 :     TagObject(js_fun->context(), "(context)");
     836             :     SetInternalReference(entry, "context", js_fun->context(),
     837      277022 :                          JSFunction::kContextOffset);
     838             :     SetInternalReference(entry, "code", js_fun->code(),
     839      277022 :                          JSFunction::kCodeOffset);
     840      140628 :   } else if (obj->IsJSGlobalObject()) {
     841         393 :     JSGlobalObject global_obj = JSGlobalObject::cast(obj);
     842             :     SetInternalReference(entry, "native_context", global_obj->native_context(),
     843         393 :                          JSGlobalObject::kNativeContextOffset);
     844             :     SetInternalReference(entry, "global_proxy", global_obj->global_proxy(),
     845         393 :                          JSGlobalObject::kGlobalProxyOffset);
     846             :     STATIC_ASSERT(JSGlobalObject::kSize - JSObject::kHeaderSize ==
     847             :                   2 * kTaggedSize);
     848      140235 :   } else if (obj->IsJSArrayBufferView()) {
     849             :     JSArrayBufferView view = JSArrayBufferView::cast(obj);
     850             :     SetInternalReference(entry, "buffer", view->buffer(),
     851           5 :                          JSArrayBufferView::kBufferOffset);
     852             :   }
     853             : 
     854      418048 :   TagObject(js_obj->raw_properties_or_hash(), "(object properties)");
     855             :   SetInternalReference(entry, "properties", js_obj->raw_properties_or_hash(),
     856      418048 :                        JSObject::kPropertiesOrHashOffset);
     857             : 
     858      418048 :   TagObject(js_obj->elements(), "(object elements)");
     859             :   SetInternalReference(entry, "elements", js_obj->elements(),
     860      418048 :                        JSObject::kElementsOffset);
     861      418048 : }
     862             : 
     863      599439 : void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, String string) {
     864      599439 :   if (string->IsConsString()) {
     865      120020 :     ConsString cs = ConsString::cast(string);
     866      120020 :     SetInternalReference(entry, "first", cs->first(), ConsString::kFirstOffset);
     867             :     SetInternalReference(entry, "second", cs->second(),
     868      120020 :                          ConsString::kSecondOffset);
     869      479419 :   } else if (string->IsSlicedString()) {
     870           5 :     SlicedString ss = SlicedString::cast(string);
     871             :     SetInternalReference(entry, "parent", ss->parent(),
     872           5 :                          SlicedString::kParentOffset);
     873      479414 :   } else if (string->IsThinString()) {
     874           0 :     ThinString ts = ThinString::cast(string);
     875             :     SetInternalReference(entry, "actual", ts->actual(),
     876           0 :                          ThinString::kActualOffset);
     877             :   }
     878      599439 : }
     879             : 
     880           0 : void V8HeapExplorer::ExtractSymbolReferences(HeapEntry* entry, Symbol symbol) {
     881        6602 :   SetInternalReference(entry, "name", symbol->name(), Symbol::kNameOffset);
     882           0 : }
     883             : 
     884           0 : void V8HeapExplorer::ExtractJSCollectionReferences(HeapEntry* entry,
     885             :                                                    JSCollection collection) {
     886             :   SetInternalReference(entry, "table", collection->table(),
     887          10 :                        JSCollection::kTableOffset);
     888           0 : }
     889             : 
     890           0 : void V8HeapExplorer::ExtractJSWeakCollectionReferences(HeapEntry* entry,
     891             :                                                        JSWeakCollection obj) {
     892             :   SetInternalReference(entry, "table", obj->table(),
     893          15 :                        JSWeakCollection::kTableOffset);
     894           0 : }
     895             : 
     896          15 : void V8HeapExplorer::ExtractEphemeronHashTableReferences(
     897             :     HeapEntry* entry, EphemeronHashTable table) {
     898          75 :   for (int i = 0, capacity = table->Capacity(); i < capacity; ++i) {
     899             :     int key_index = EphemeronHashTable::EntryToIndex(i) +
     900             :                     EphemeronHashTable::kEntryKeyIndex;
     901             :     int value_index = EphemeronHashTable::EntryToValueIndex(i);
     902          60 :     Object key = table->get(key_index);
     903          60 :     Object value = table->get(value_index);
     904             :     SetWeakReference(entry, key_index, key,
     905          60 :                      table->OffsetOfElementAt(key_index));
     906             :     SetWeakReference(entry, value_index, value,
     907          60 :                      table->OffsetOfElementAt(value_index));
     908         120 :     HeapEntry* key_entry = GetEntry(key);
     909          60 :     HeapEntry* value_entry = GetEntry(value);
     910          60 :     if (key_entry && value_entry) {
     911             :       const char* edge_name =
     912          60 :           names_->GetFormatted("key %s in WeakMap", key_entry->name());
     913             :       key_entry->SetNamedAutoIndexReference(HeapGraphEdge::kInternal, edge_name,
     914          60 :                                             value_entry, names_);
     915             :     }
     916             :   }
     917          15 : }
     918             : 
     919             : // These static arrays are used to prevent excessive code-size in
     920             : // ExtractContextReferences below, which would happen if we called
     921             : // SetInternalReference for every native context field in a macro.
     922             : static const struct {
     923             :   int index;
     924             :   const char* name;
     925             : } native_context_names[] = {
     926             : #define CONTEXT_FIELD_INDEX_NAME(index, _, name) {Context::index, #name},
     927             :     NATIVE_CONTEXT_FIELDS(CONTEXT_FIELD_INDEX_NAME)
     928             : #undef CONTEXT_FIELD_INDEX_NAME
     929             : };
     930             : 
     931        2433 : void V8HeapExplorer::ExtractContextReferences(HeapEntry* entry,
     932             :                                               Context context) {
     933        2433 :   if (!context->IsNativeContext() && context->is_declaration_context()) {
     934        2010 :     ScopeInfo scope_info = context->scope_info();
     935             :     // Add context allocated locals.
     936        2010 :     int context_locals = scope_info->ContextLocalCount();
     937       35597 :     for (int i = 0; i < context_locals; ++i) {
     938       33587 :       String local_name = scope_info->ContextLocalName(i);
     939             :       int idx = Context::MIN_CONTEXT_SLOTS + i;
     940             :       SetContextReference(entry, local_name, context->get(idx),
     941       33587 :                           Context::OffsetOfElementAt(idx));
     942             :     }
     943        2010 :     if (scope_info->HasFunctionName()) {
     944         876 :       String name = String::cast(scope_info->FunctionName());
     945         438 :       int idx = scope_info->FunctionContextSlotIndex(name);
     946         438 :       if (idx >= 0) {
     947             :         SetContextReference(entry, name, context->get(idx),
     948           0 :                             Context::OffsetOfElementAt(idx));
     949             :       }
     950             :     }
     951             :   }
     952             : 
     953             :   SetInternalReference(
     954             :       entry, "scope_info", context->get(Context::SCOPE_INFO_INDEX),
     955        2433 :       FixedArray::OffsetOfElementAt(Context::SCOPE_INFO_INDEX));
     956             :   SetInternalReference(entry, "previous", context->get(Context::PREVIOUS_INDEX),
     957        2433 :                        FixedArray::OffsetOfElementAt(Context::PREVIOUS_INDEX));
     958             :   SetInternalReference(entry, "extension",
     959             :                        context->get(Context::EXTENSION_INDEX),
     960        2433 :                        FixedArray::OffsetOfElementAt(Context::EXTENSION_INDEX));
     961             :   SetInternalReference(
     962             :       entry, "native_context", context->get(Context::NATIVE_CONTEXT_INDEX),
     963        2433 :       FixedArray::OffsetOfElementAt(Context::NATIVE_CONTEXT_INDEX));
     964             : 
     965        2433 :   if (context->IsNativeContext()) {
     966         393 :     TagObject(context->normalized_map_cache(), "(context norm. map cache)");
     967         393 :     TagObject(context->embedder_data(), "(context data)");
     968       93927 :     for (size_t i = 0; i < arraysize(native_context_names); i++) {
     969       93534 :       int index = native_context_names[i].index;
     970       93534 :       const char* name = native_context_names[i].name;
     971             :       SetInternalReference(entry, name, context->get(index),
     972       93534 :                            FixedArray::OffsetOfElementAt(index));
     973             :     }
     974             : 
     975             :     SetWeakReference(
     976             :         entry, "optimized_code_list",
     977             :         context->get(Context::OPTIMIZED_CODE_LIST),
     978         393 :         FixedArray::OffsetOfElementAt(Context::OPTIMIZED_CODE_LIST));
     979             :     SetWeakReference(
     980             :         entry, "deoptimized_code_list",
     981             :         context->get(Context::DEOPTIMIZED_CODE_LIST),
     982         393 :         FixedArray::OffsetOfElementAt(Context::DEOPTIMIZED_CODE_LIST));
     983             :     STATIC_ASSERT(Context::OPTIMIZED_CODE_LIST == Context::FIRST_WEAK_SLOT);
     984             :     STATIC_ASSERT(Context::NEXT_CONTEXT_LINK + 1 ==
     985             :                   Context::NATIVE_CONTEXT_SLOTS);
     986             :     STATIC_ASSERT(Context::FIRST_WEAK_SLOT + 3 ==
     987             :                   Context::NATIVE_CONTEXT_SLOTS);
     988             :   }
     989        2433 : }
     990             : 
     991      136650 : void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map map) {
     992      136650 :   MaybeObject maybe_raw_transitions_or_prototype_info = map->raw_transitions();
     993      136650 :   HeapObject raw_transitions_or_prototype_info;
     994      136650 :   if (maybe_raw_transitions_or_prototype_info->GetHeapObjectIfWeak(
     995             :           &raw_transitions_or_prototype_info)) {
     996             :     DCHECK(raw_transitions_or_prototype_info->IsMap());
     997             :     SetWeakReference(entry, "transition", raw_transitions_or_prototype_info,
     998         189 :                      Map::kTransitionsOrPrototypeInfoOffset);
     999      136461 :   } else if (maybe_raw_transitions_or_prototype_info->GetHeapObjectIfStrong(
    1000             :                  &raw_transitions_or_prototype_info)) {
    1001       25903 :     if (raw_transitions_or_prototype_info->IsTransitionArray()) {
    1002             :       TransitionArray transitions =
    1003        2756 :           TransitionArray::cast(raw_transitions_or_prototype_info);
    1004        5512 :       if (map->CanTransition() && transitions->HasPrototypeTransitions()) {
    1005             :         TagObject(transitions->GetPrototypeTransitions(),
    1006         393 :                   "(prototype transitions)");
    1007             :       }
    1008        2756 :       TagObject(transitions, "(transition array)");
    1009             :       SetInternalReference(entry, "transitions", transitions,
    1010        2756 :                            Map::kTransitionsOrPrototypeInfoOffset);
    1011       46294 :     } else if (raw_transitions_or_prototype_info->IsTuple3() ||
    1012             :                raw_transitions_or_prototype_info->IsFixedArray()) {
    1013           0 :       TagObject(raw_transitions_or_prototype_info, "(transition)");
    1014             :       SetInternalReference(entry, "transition",
    1015             :                            raw_transitions_or_prototype_info,
    1016           0 :                            Map::kTransitionsOrPrototypeInfoOffset);
    1017       23147 :     } else if (map->is_prototype_map()) {
    1018       23147 :       TagObject(raw_transitions_or_prototype_info, "prototype_info");
    1019             :       SetInternalReference(entry, "prototype_info",
    1020             :                            raw_transitions_or_prototype_info,
    1021       23147 :                            Map::kTransitionsOrPrototypeInfoOffset);
    1022             :     }
    1023             :   }
    1024      136650 :   DescriptorArray descriptors = map->instance_descriptors();
    1025      136650 :   TagObject(descriptors, "(map descriptors)");
    1026             :   SetInternalReference(entry, "descriptors", descriptors,
    1027      136650 :                        Map::kDescriptorsOffset);
    1028             :   SetInternalReference(entry, "prototype", map->prototype(),
    1029      136650 :                        Map::kPrototypeOffset);
    1030             :   if (FLAG_unbox_double_fields) {
    1031             :     SetInternalReference(entry, "layout_descriptor", map->layout_descriptor(),
    1032      136650 :                          Map::kLayoutDescriptorOffset);
    1033             :   }
    1034      136650 :   Object constructor_or_backpointer = map->constructor_or_backpointer();
    1035      136650 :   if (constructor_or_backpointer->IsMap()) {
    1036        2164 :     TagObject(constructor_or_backpointer, "(back pointer)");
    1037             :     SetInternalReference(entry, "back_pointer", constructor_or_backpointer,
    1038        2164 :                          Map::kConstructorOrBackPointerOffset);
    1039      134486 :   } else if (constructor_or_backpointer->IsFunctionTemplateInfo()) {
    1040           0 :     TagObject(constructor_or_backpointer, "(constructor function data)");
    1041             :     SetInternalReference(entry, "constructor_function_data",
    1042             :                          constructor_or_backpointer,
    1043           0 :                          Map::kConstructorOrBackPointerOffset);
    1044             :   } else {
    1045             :     SetInternalReference(entry, "constructor", constructor_or_backpointer,
    1046      134486 :                          Map::kConstructorOrBackPointerOffset);
    1047             :   }
    1048      136650 :   TagObject(map->dependent_code(), "(dependent code)");
    1049             :   SetInternalReference(entry, "dependent_code", map->dependent_code(),
    1050      136650 :                        Map::kDependentCodeOffset);
    1051      136650 : }
    1052             : 
    1053      284842 : void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
    1054             :     HeapEntry* entry, SharedFunctionInfo shared) {
    1055      284842 :   String shared_name = shared->DebugName();
    1056             :   const char* name = nullptr;
    1057      569684 :   if (shared_name != ReadOnlyRoots(heap_).empty_string()) {
    1058      265217 :     name = names_->GetName(shared_name);
    1059      265217 :     TagObject(shared->GetCode(), names_->GetFormatted("(code for %s)", name));
    1060             :   } else {
    1061             :     TagObject(shared->GetCode(),
    1062             :               names_->GetFormatted(
    1063       39250 :                   "(%s code)", Code::Kind2String(shared->GetCode()->kind())));
    1064             :   }
    1065             : 
    1066      569684 :   if (shared->name_or_scope_info()->IsScopeInfo()) {
    1067         850 :     TagObject(shared->name_or_scope_info(), "(function scope info)");
    1068             :   }
    1069             :   SetInternalReference(entry, "name_or_scope_info",
    1070             :                        shared->name_or_scope_info(),
    1071      284842 :                        SharedFunctionInfo::kNameOrScopeInfoOffset);
    1072             :   SetInternalReference(entry, "script_or_debug_info",
    1073             :                        shared->script_or_debug_info(),
    1074      284842 :                        SharedFunctionInfo::kScriptOrDebugInfoOffset);
    1075             :   SetInternalReference(entry, "function_data", shared->function_data(),
    1076      284842 :                        SharedFunctionInfo::kFunctionDataOffset);
    1077             :   SetInternalReference(
    1078             :       entry, "raw_outer_scope_info_or_feedback_metadata",
    1079             :       shared->raw_outer_scope_info_or_feedback_metadata(),
    1080      284842 :       SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset);
    1081      284842 : }
    1082             : 
    1083        1487 : void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script script) {
    1084             :   SetInternalReference(entry, "source", script->source(),
    1085        1487 :                        Script::kSourceOffset);
    1086        1487 :   SetInternalReference(entry, "name", script->name(), Script::kNameOffset);
    1087             :   SetInternalReference(entry, "context_data", script->context_data(),
    1088        1487 :                        Script::kContextOffset);
    1089        1487 :   TagObject(script->line_ends(), "(script line ends)");
    1090             :   SetInternalReference(entry, "line_ends", script->line_ends(),
    1091        1487 :                        Script::kLineEndsOffset);
    1092        1487 : }
    1093             : 
    1094        4323 : void V8HeapExplorer::ExtractAccessorInfoReferences(HeapEntry* entry,
    1095             :                                                    AccessorInfo accessor_info) {
    1096             :   SetInternalReference(entry, "name", accessor_info->name(),
    1097        4323 :                        AccessorInfo::kNameOffset);
    1098             :   SetInternalReference(entry, "expected_receiver_type",
    1099             :                        accessor_info->expected_receiver_type(),
    1100        4323 :                        AccessorInfo::kExpectedReceiverTypeOffset);
    1101             :   SetInternalReference(entry, "getter", accessor_info->getter(),
    1102        4323 :                        AccessorInfo::kGetterOffset);
    1103             :   SetInternalReference(entry, "setter", accessor_info->setter(),
    1104        4323 :                        AccessorInfo::kSetterOffset);
    1105             :   SetInternalReference(entry, "data", accessor_info->data(),
    1106        4323 :                        AccessorInfo::kDataOffset);
    1107        4323 : }
    1108             : 
    1109       24501 : void V8HeapExplorer::ExtractAccessorPairReferences(HeapEntry* entry,
    1110             :                                                    AccessorPair accessors) {
    1111             :   SetInternalReference(entry, "getter", accessors->getter(),
    1112       24501 :                        AccessorPair::kGetterOffset);
    1113             :   SetInternalReference(entry, "setter", accessors->setter(),
    1114       24501 :                        AccessorPair::kSetterOffset);
    1115       24501 : }
    1116             : 
    1117      598990 : void V8HeapExplorer::TagBuiltinCodeObject(Code code, const char* name) {
    1118      598990 :   TagObject(code, names_->GetFormatted("(%s builtin)", name));
    1119      598990 : }
    1120             : 
    1121      592929 : void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code code) {
    1122      592929 :   TagObject(code->relocation_info(), "(code relocation info)");
    1123             :   SetInternalReference(entry, "relocation_info", code->relocation_info(),
    1124      592929 :                        Code::kRelocationInfoOffset);
    1125      592929 :   TagObject(code->deoptimization_data(), "(code deopt data)");
    1126             :   SetInternalReference(entry, "deoptimization_data",
    1127             :                        code->deoptimization_data(),
    1128      592929 :                        Code::kDeoptimizationDataOffset);
    1129      592929 :   TagObject(code->source_position_table(), "(source position table)");
    1130             :   SetInternalReference(entry, "source_position_table",
    1131             :                        code->source_position_table(),
    1132      592929 :                        Code::kSourcePositionTableOffset);
    1133      592929 : }
    1134             : 
    1135           0 : void V8HeapExplorer::ExtractCellReferences(HeapEntry* entry, Cell cell) {
    1136        3065 :   SetInternalReference(entry, "value", cell->value(), Cell::kValueOffset);
    1137           0 : }
    1138             : 
    1139       34874 : void V8HeapExplorer::ExtractFeedbackCellReferences(HeapEntry* entry,
    1140             :                                                    FeedbackCell feedback_cell) {
    1141       34874 :   TagObject(feedback_cell, "(feedback cell)");
    1142             :   SetInternalReference(entry, "value", feedback_cell->value(),
    1143       34874 :                        FeedbackCell::kValueOffset);
    1144       34874 : }
    1145             : 
    1146       28438 : void V8HeapExplorer::ExtractPropertyCellReferences(HeapEntry* entry,
    1147             :                                                    PropertyCell cell) {
    1148             :   SetInternalReference(entry, "value", cell->value(),
    1149       28438 :                        PropertyCell::kValueOffset);
    1150       28438 :   TagObject(cell->dependent_code(), "(dependent code)");
    1151             :   SetInternalReference(entry, "dependent_code", cell->dependent_code(),
    1152       28438 :                        PropertyCell::kDependentCodeOffset);
    1153       28438 : }
    1154             : 
    1155          16 : void V8HeapExplorer::ExtractAllocationSiteReferences(HeapEntry* entry,
    1156             :                                                      AllocationSite site) {
    1157             :   SetInternalReference(entry, "transition_info",
    1158             :                        site->transition_info_or_boilerplate(),
    1159          16 :                        AllocationSite::kTransitionInfoOrBoilerplateOffset);
    1160             :   SetInternalReference(entry, "nested_site", site->nested_site(),
    1161          16 :                        AllocationSite::kNestedSiteOffset);
    1162          16 :   TagObject(site->dependent_code(), "(dependent code)");
    1163             :   SetInternalReference(entry, "dependent_code", site->dependent_code(),
    1164          16 :                        AllocationSite::kDependentCodeOffset);
    1165          16 : }
    1166             : 
    1167          25 : void V8HeapExplorer::ExtractArrayBoilerplateDescriptionReferences(
    1168             :     HeapEntry* entry, ArrayBoilerplateDescription value) {
    1169             :   SetInternalReference(entry, "constant_elements", value->constant_elements(),
    1170          25 :                        ArrayBoilerplateDescription::kConstantElementsOffset);
    1171          25 : }
    1172             : 
    1173           0 : class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator {
    1174             :  public:
    1175             :   JSArrayBufferDataEntryAllocator(size_t size, V8HeapExplorer* explorer)
    1176             :       : size_(size)
    1177          15 :       , explorer_(explorer) {
    1178             :   }
    1179          10 :   HeapEntry* AllocateEntry(HeapThing ptr) override {
    1180             :     return explorer_->AddEntry(reinterpret_cast<Address>(ptr),
    1181             :                                HeapEntry::kNative, "system / JSArrayBufferData",
    1182          10 :                                size_);
    1183             :   }
    1184             :  private:
    1185             :   size_t size_;
    1186             :   V8HeapExplorer* explorer_;
    1187             : };
    1188             : 
    1189          15 : void V8HeapExplorer::ExtractJSArrayBufferReferences(HeapEntry* entry,
    1190             :                                                     JSArrayBuffer buffer) {
    1191             :   // Setup a reference to a native memory backing_store object.
    1192          15 :   if (!buffer->backing_store()) return;
    1193             :   size_t data_size = buffer->byte_length();
    1194             :   JSArrayBufferDataEntryAllocator allocator(data_size, this);
    1195             :   HeapEntry* data_entry =
    1196          15 :       generator_->FindOrAddEntry(buffer->backing_store(), &allocator);
    1197             :   entry->SetNamedReference(HeapGraphEdge::kInternal, "backing_store",
    1198             :                            data_entry);
    1199             : }
    1200             : 
    1201           0 : void V8HeapExplorer::ExtractJSPromiseReferences(HeapEntry* entry,
    1202             :                                                 JSPromise promise) {
    1203             :   SetInternalReference(entry, "reactions_or_result",
    1204             :                        promise->reactions_or_result(),
    1205          25 :                        JSPromise::kReactionsOrResultOffset);
    1206           0 : }
    1207             : 
    1208          10 : void V8HeapExplorer::ExtractJSGeneratorObjectReferences(
    1209             :     HeapEntry* entry, JSGeneratorObject generator) {
    1210             :   SetInternalReference(entry, "function", generator->function(),
    1211          10 :                        JSGeneratorObject::kFunctionOffset);
    1212             :   SetInternalReference(entry, "context", generator->context(),
    1213          10 :                        JSGeneratorObject::kContextOffset);
    1214             :   SetInternalReference(entry, "receiver", generator->receiver(),
    1215          10 :                        JSGeneratorObject::kReceiverOffset);
    1216             :   SetInternalReference(entry, "parameters_and_registers",
    1217             :                        generator->parameters_and_registers(),
    1218          10 :                        JSGeneratorObject::kParametersAndRegistersOffset);
    1219          10 : }
    1220             : 
    1221       10029 : void V8HeapExplorer::ExtractFixedArrayReferences(HeapEntry* entry,
    1222             :                                                  FixedArray array) {
    1223     2839062 :   for (int i = 0, l = array->length(); i < l; ++i) {
    1224             :     DCHECK(!HasWeakHeapObjectTag(array->get(i)));
    1225     2829033 :     SetInternalReference(entry, i, array->get(i), array->OffsetOfElementAt(i));
    1226             :   }
    1227       10029 : }
    1228             : 
    1229         448 : void V8HeapExplorer::ExtractFeedbackVectorReferences(
    1230             :     HeapEntry* entry, FeedbackVector feedback_vector) {
    1231         448 :   MaybeObject code = feedback_vector->optimized_code_weak_or_smi();
    1232         448 :   HeapObject code_heap_object;
    1233         448 :   if (code->GetHeapObjectIfWeak(&code_heap_object)) {
    1234             :     SetWeakReference(entry, "optimized code", code_heap_object,
    1235           4 :                      FeedbackVector::kOptimizedCodeOffset);
    1236             :   }
    1237         448 : }
    1238             : 
    1239       79991 : void V8HeapExplorer::ExtractDescriptorArrayReferences(HeapEntry* entry,
    1240             :                                                       DescriptorArray array) {
    1241             :   SetInternalReference(entry, "enum_cache", array->enum_cache(),
    1242       79991 :                        DescriptorArray::kEnumCacheOffset);
    1243             :   MaybeObjectSlot start = MaybeObjectSlot(array->GetDescriptorSlot(0));
    1244             :   MaybeObjectSlot end = MaybeObjectSlot(
    1245       79991 :       array->GetDescriptorSlot(array->number_of_all_descriptors()));
    1246     2740966 :   for (int i = 0; start + i < end; ++i) {
    1247             :     MaybeObjectSlot slot = start + i;
    1248     2580984 :     int offset = static_cast<int>(slot.address() - array->address());
    1249     1290492 :     MaybeObject object = *slot;
    1250     1290492 :     HeapObject heap_object;
    1251     1290492 :     if (object->GetHeapObjectIfWeak(&heap_object)) {
    1252        4282 :       SetWeakReference(entry, i, heap_object, offset);
    1253     1286210 :     } else if (object->GetHeapObjectIfStrong(&heap_object)) {
    1254      553576 :       SetInternalReference(entry, i, heap_object, offset);
    1255             :     }
    1256             :   }
    1257       79991 : }
    1258             : 
    1259             : template <typename T>
    1260        6610 : void V8HeapExplorer::ExtractWeakArrayReferences(int header_size,
    1261             :                                                 HeapEntry* entry, T array) {
    1262      675828 :   for (int i = 0; i < array->length(); ++i) {
    1263      331304 :     MaybeObject object = array->Get(i);
    1264      331304 :     HeapObject heap_object;
    1265      331304 :     if (object->GetHeapObjectIfWeak(&heap_object)) {
    1266      288736 :       SetWeakReference(entry, i, heap_object, header_size + i * kTaggedSize);
    1267       42568 :     } else if (object->GetHeapObjectIfStrong(&heap_object)) {
    1268       35303 :       SetInternalReference(entry, i, heap_object,
    1269       35303 :                            header_size + i * kTaggedSize);
    1270             :     }
    1271             :   }
    1272        6610 : }
    1273             : 
    1274      418048 : void V8HeapExplorer::ExtractPropertyReferences(JSObject js_obj,
    1275             :                                                HeapEntry* entry) {
    1276             :   Isolate* isolate = js_obj->GetIsolate();
    1277      418048 :   if (js_obj->HasFastProperties()) {
    1278      417475 :     DescriptorArray descs = js_obj->map()->instance_descriptors();
    1279             :     int real_size = js_obj->map()->NumberOfOwnDescriptors();
    1280     1432570 :     for (int i = 0; i < real_size; i++) {
    1281     1015095 :       PropertyDetails details = descs->GetDetails(i);
    1282     1015095 :       switch (details.location()) {
    1283             :         case kField: {
    1284             :           Representation r = details.representation();
    1285      291955 :           if (r.IsSmi() || r.IsDouble()) break;
    1286             : 
    1287      264028 :           Name k = descs->GetKey(i);
    1288      264028 :           FieldIndex field_index = FieldIndex::ForDescriptor(js_obj->map(), i);
    1289      264028 :           Object value = js_obj->RawFastPropertyAt(field_index);
    1290             :           int field_offset =
    1291      264028 :               field_index.is_inobject() ? field_index.offset() : -1;
    1292             : 
    1293             :           SetDataOrAccessorPropertyReference(details.kind(), entry, k, value,
    1294      264028 :                                              nullptr, field_offset);
    1295      264028 :           break;
    1296             :         }
    1297             :         case kDescriptor:
    1298             :           SetDataOrAccessorPropertyReference(details.kind(), entry,
    1299             :                                              descs->GetKey(i),
    1300     1446280 :                                              descs->GetStrongValue(i));
    1301      723140 :           break;
    1302             :       }
    1303             :     }
    1304         573 :   } else if (js_obj->IsJSGlobalObject()) {
    1305             :     // We assume that global objects can only have slow properties.
    1306             :     GlobalDictionary dictionary =
    1307         393 :         JSGlobalObject::cast(js_obj)->global_dictionary();
    1308         393 :     int length = dictionary->Capacity();
    1309             :     ReadOnlyRoots roots(isolate);
    1310       50697 :     for (int i = 0; i < length; ++i) {
    1311      127190 :       if (!dictionary->IsKey(roots, dictionary->KeyAt(i))) continue;
    1312       23722 :       PropertyCell cell = dictionary->CellAt(i);
    1313       23722 :       Name name = cell->name();
    1314       23722 :       Object value = cell->value();
    1315       23722 :       PropertyDetails details = cell->property_details();
    1316       23722 :       SetDataOrAccessorPropertyReference(details.kind(), entry, name, value);
    1317             :     }
    1318             :   } else {
    1319         180 :     NameDictionary dictionary = js_obj->property_dictionary();
    1320         180 :     int length = dictionary->Capacity();
    1321             :     ReadOnlyRoots roots(isolate);
    1322        2280 :     for (int i = 0; i < length; ++i) {
    1323        2100 :       Object k = dictionary->KeyAt(i);
    1324        3510 :       if (!dictionary->IsKey(roots, k)) continue;
    1325         690 :       Object value = dictionary->ValueAt(i);
    1326         690 :       PropertyDetails details = dictionary->DetailsAt(i);
    1327             :       SetDataOrAccessorPropertyReference(details.kind(), entry, Name::cast(k),
    1328         690 :                                          value);
    1329             :     }
    1330             :   }
    1331      418048 : }
    1332             : 
    1333      723155 : void V8HeapExplorer::ExtractAccessorPairProperty(HeapEntry* entry, Name key,
    1334             :                                                  Object callback_obj,
    1335             :                                                  int field_offset) {
    1336     1421809 :   if (!callback_obj->IsAccessorPair()) return;
    1337             :   AccessorPair accessors = AccessorPair::cast(callback_obj);
    1338       24501 :   SetPropertyReference(entry, key, accessors, nullptr, field_offset);
    1339       24501 :   Object getter = accessors->getter();
    1340       24501 :   if (!getter->IsOddball()) {
    1341       24491 :     SetPropertyReference(entry, key, getter, "get %s");
    1342             :   }
    1343       24501 :   Object setter = accessors->setter();
    1344       24501 :   if (!setter->IsOddball()) {
    1345        9002 :     SetPropertyReference(entry, key, setter, "set %s");
    1346             :   }
    1347             : }
    1348             : 
    1349      418048 : void V8HeapExplorer::ExtractElementReferences(JSObject js_obj,
    1350             :                                               HeapEntry* entry) {
    1351      418048 :   ReadOnlyRoots roots = js_obj->GetReadOnlyRoots();
    1352      418048 :   if (js_obj->HasObjectElements()) {
    1353      834514 :     FixedArray elements = FixedArray::cast(js_obj->elements());
    1354             :     int length = js_obj->IsJSArray()
    1355             :                      ? Smi::ToInt(JSArray::cast(js_obj)->length())
    1356      417691 :                      : elements->length();
    1357      547478 :     for (int i = 0; i < length; ++i) {
    1358      260442 :       if (!elements->get(i)->IsTheHole(roots)) {
    1359      130131 :         SetElementReference(entry, i, elements->get(i));
    1360             :       }
    1361             :     }
    1362         791 :   } else if (js_obj->HasDictionaryElements()) {
    1363         393 :     NumberDictionary dictionary = js_obj->element_dictionary();
    1364         393 :     int length = dictionary->Capacity();
    1365         786 :     for (int i = 0; i < length; ++i) {
    1366         393 :       Object k = dictionary->KeyAt(i);
    1367         786 :       if (!dictionary->IsKey(roots, k)) continue;
    1368             :       DCHECK(k->IsNumber());
    1369           0 :       uint32_t index = static_cast<uint32_t>(k->Number());
    1370           0 :       SetElementReference(entry, index, dictionary->ValueAt(i));
    1371             :     }
    1372             :   }
    1373      418048 : }
    1374             : 
    1375      418048 : void V8HeapExplorer::ExtractInternalReferences(JSObject js_obj,
    1376             :                                                HeapEntry* entry) {
    1377      418048 :   int length = js_obj->GetEmbedderFieldCount();
    1378      418143 :   for (int i = 0; i < length; ++i) {
    1379          95 :     Object o = js_obj->GetEmbedderField(i);
    1380          95 :     SetInternalReference(entry, i, o, js_obj->GetEmbedderFieldOffset(i));
    1381             :   }
    1382      418048 : }
    1383             : 
    1384      141454 : JSFunction V8HeapExplorer::GetConstructor(JSReceiver receiver) {
    1385             :   Isolate* isolate = receiver->GetIsolate();
    1386             :   DisallowHeapAllocation no_gc;
    1387             :   HandleScope scope(isolate);
    1388             :   MaybeHandle<JSFunction> maybe_constructor =
    1389      141454 :       JSReceiver::GetConstructor(handle(receiver, isolate));
    1390             : 
    1391      141454 :   if (maybe_constructor.is_null()) return JSFunction();
    1392             : 
    1393             :   return *maybe_constructor.ToHandleChecked();
    1394             : }
    1395             : 
    1396      141071 : String V8HeapExplorer::GetConstructorName(JSObject object) {
    1397             :   Isolate* isolate = object->GetIsolate();
    1398      141071 :   if (object->IsJSFunction()) return ReadOnlyRoots(isolate).closure_string();
    1399             :   DisallowHeapAllocation no_gc;
    1400             :   HandleScope scope(isolate);
    1401      282142 :   return *JSReceiver::GetConstructorName(handle(object, isolate));
    1402             : }
    1403             : 
    1404    22722476 : HeapEntry* V8HeapExplorer::GetEntry(Object obj) {
    1405             :   return obj->IsHeapObject() ? generator_->FindOrAddEntry(
    1406    44125340 :                                    reinterpret_cast<void*>(obj.ptr()), this)
    1407    44785146 :                              : nullptr;
    1408             : }
    1409             : 
    1410           0 : class RootsReferencesExtractor : public RootVisitor {
    1411             :  public:
    1412             :   explicit RootsReferencesExtractor(V8HeapExplorer* explorer)
    1413         398 :       : explorer_(explorer), visiting_weak_roots_(false) {}
    1414             : 
    1415         398 :   void SetVisitingWeakRoots() { visiting_weak_roots_ = true; }
    1416             : 
    1417     1447794 :   void VisitRootPointer(Root root, const char* description,
    1418             :                         FullObjectSlot object) override {
    1419     1447794 :     if (root == Root::kBuiltins) {
    1420      598990 :       explorer_->TagBuiltinCodeObject(Code::cast(*object), description);
    1421             :     }
    1422             :     explorer_->SetGcSubrootReference(root, description, visiting_weak_roots_,
    1423     1447794 :                                      *object);
    1424     1447794 :   }
    1425             : 
    1426        4318 :   void VisitRootPointers(Root root, const char* description,
    1427             :                          FullObjectSlot start, FullObjectSlot end) override {
    1428      250573 :     for (FullObjectSlot p = start; p < end; ++p) {
    1429      241937 :       VisitRootPointer(root, description, p);
    1430             :     }
    1431        4318 :   }
    1432             : 
    1433             :  private:
    1434             :   V8HeapExplorer* explorer_;
    1435             :   bool visiting_weak_roots_;
    1436             : };
    1437             : 
    1438         398 : bool V8HeapExplorer::IterateAndExtractReferences(
    1439             :     HeapSnapshotGenerator* generator) {
    1440         398 :   generator_ = generator;
    1441             : 
    1442             :   // Create references to the synthetic roots.
    1443             :   SetRootGcRootsReference();
    1444        9950 :   for (int root = 0; root < static_cast<int>(Root::kNumberOfRoots); root++) {
    1445             :     SetGcRootsReference(static_cast<Root>(root));
    1446             :   }
    1447             : 
    1448             :   // Make sure builtin code objects get their builtin tags
    1449             :   // first. Otherwise a particular JSFunction object could set
    1450             :   // its custom name to a generic builtin.
    1451             :   RootsReferencesExtractor extractor(this);
    1452         796 :   ReadOnlyRoots(heap_).Iterate(&extractor);
    1453         398 :   heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG);
    1454             :   extractor.SetVisitingWeakRoots();
    1455         398 :   heap_->IterateWeakGlobalHandles(&extractor);
    1456             : 
    1457             :   bool interrupted = false;
    1458             : 
    1459         796 :   HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable);
    1460             :   // Heap iteration with filtering must be finished in any case.
    1461     6048978 :   for (HeapObject obj = iterator.next(); !obj.is_null();
    1462     3024091 :        obj = iterator.next(), progress_->ProgressStep()) {
    1463     3056390 :     if (interrupted) continue;
    1464             : 
    1465     2991792 :     size_t max_pointer = obj->Size() / kTaggedSize;
    1466     2991792 :     if (max_pointer > visited_fields_.size()) {
    1467             :       // Clear the current bits.
    1468             :       std::vector<bool>().swap(visited_fields_);
    1469             :       // Reallocate to right size.
    1470        2357 :       visited_fields_.resize(max_pointer, false);
    1471             :     }
    1472             : 
    1473     2991792 :     HeapEntry* entry = GetEntry(obj);
    1474     2991792 :     ExtractReferences(entry, obj);
    1475     2991792 :     SetInternalReference(entry, "map", obj->map(), HeapObject::kMapOffset);
    1476             :     // Extract unvisited fields as hidden references and restore tags
    1477             :     // of visited fields.
    1478     2991792 :     IndexedReferencesExtractor refs_extractor(this, obj, entry);
    1479     2991792 :     obj->Iterate(&refs_extractor);
    1480             : 
    1481             :     // Ensure visited_fields_ doesn't leak to the next object.
    1482             :     for (size_t i = 0; i < max_pointer; ++i) {
    1483             :       DCHECK(!visited_fields_[i]);
    1484             :     }
    1485             : 
    1486             :     // Extract location for specific object types
    1487     2991792 :     ExtractLocation(entry, obj);
    1488             : 
    1489     2991792 :     if (!progress_->ProgressReport(false)) interrupted = true;
    1490             :   }
    1491             : 
    1492         398 :   generator_ = nullptr;
    1493         796 :   return interrupted ? false : progress_->ProgressReport(true);
    1494             : }
    1495             : 
    1496    18852322 : bool V8HeapExplorer::IsEssentialObject(Object object) {
    1497    18852322 :   ReadOnlyRoots roots(heap_);
    1498    34503078 :   return object->IsHeapObject() && !object->IsOddball() &&
    1499    14465015 :          object != roots.empty_byte_array() &&
    1500    11722900 :          object != roots.empty_fixed_array() &&
    1501    11392329 :          object != roots.empty_weak_fixed_array() &&
    1502    11282175 :          object != roots.empty_descriptor_array() &&
    1503    22551579 :          object != roots.fixed_array_map() && object != roots.cell_map() &&
    1504    11245819 :          object != roots.global_property_cell_map() &&
    1505    10960977 :          object != roots.shared_function_info_map() &&
    1506    10960977 :          object != roots.free_space_map() &&
    1507    29812069 :          object != roots.one_pointer_filler_map() &&
    1508    18852322 :          object != roots.two_pointer_filler_map();
    1509             : }
    1510             : 
    1511      991897 : bool V8HeapExplorer::IsEssentialHiddenReference(Object parent,
    1512             :                                                 int field_offset) {
    1513      991897 :   if (parent->IsAllocationSite() &&
    1514             :       field_offset == AllocationSite::kWeakNextOffset)
    1515             :     return false;
    1516      991897 :   if (parent->IsCodeDataContainer() &&
    1517             :       field_offset == CodeDataContainer::kNextCodeLinkOffset)
    1518             :     return false;
    1519      991861 :   if (parent->IsContext() &&
    1520             :       field_offset == Context::OffsetOfElementAt(Context::NEXT_CONTEXT_LINK))
    1521             :     return false;
    1522      991861 :   return true;
    1523             : }
    1524             : 
    1525       33587 : void V8HeapExplorer::SetContextReference(HeapEntry* parent_entry,
    1526             :                                          String reference_name,
    1527             :                                          Object child_obj, int field_offset) {
    1528       33587 :   HeapEntry* child_entry = GetEntry(child_obj);
    1529       67174 :   if (child_entry == nullptr) return;
    1530             :   parent_entry->SetNamedReference(HeapGraphEdge::kContextVariable,
    1531       33577 :                                   names_->GetName(reference_name), child_entry);
    1532             :   MarkVisitedField(field_offset);
    1533             : }
    1534             : 
    1535           0 : void V8HeapExplorer::MarkVisitedField(int offset) {
    1536    13089322 :   if (offset < 0) return;
    1537    12389151 :   int index = offset / kTaggedSize;
    1538             :   DCHECK(!visited_fields_[index]);
    1539    12389151 :   visited_fields_[index] = true;
    1540             : }
    1541             : 
    1542          10 : void V8HeapExplorer::SetNativeBindReference(HeapEntry* parent_entry,
    1543             :                                             const char* reference_name,
    1544             :                                             Object child_obj) {
    1545          10 :   HeapEntry* child_entry = GetEntry(child_obj);
    1546          20 :   if (child_entry == nullptr) return;
    1547             :   parent_entry->SetNamedReference(HeapGraphEdge::kShortcut, reference_name,
    1548             :                                   child_entry);
    1549             : }
    1550             : 
    1551      130131 : void V8HeapExplorer::SetElementReference(HeapEntry* parent_entry, int index,
    1552             :                                          Object child_obj) {
    1553      130131 :   HeapEntry* child_entry = GetEntry(child_obj);
    1554      260262 :   if (child_entry == nullptr) return;
    1555             :   parent_entry->SetIndexedReference(HeapGraphEdge::kElement, index,
    1556             :                                     child_entry);
    1557             : }
    1558             : 
    1559     9201485 : void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry,
    1560             :                                           const char* reference_name,
    1561             :                                           Object child_obj, int field_offset) {
    1562     9201485 :   HeapEntry* child_entry = GetEntry(child_obj);
    1563    18402970 :   if (child_entry == nullptr) return;
    1564     8812188 :   if (IsEssentialObject(child_obj)) {
    1565             :     parent_entry->SetNamedReference(HeapGraphEdge::kInternal, reference_name,
    1566             :                                     child_entry);
    1567             :   }
    1568             :   MarkVisitedField(field_offset);
    1569             : }
    1570             : 
    1571     3418007 : void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry, int index,
    1572             :                                           Object child_obj, int field_offset) {
    1573     3418007 :   HeapEntry* child_entry = GetEntry(child_obj);
    1574     6836014 :   if (child_entry == nullptr) return;
    1575     3156134 :   if (IsEssentialObject(child_obj)) {
    1576             :     parent_entry->SetNamedReference(HeapGraphEdge::kInternal,
    1577     1231704 :                                     names_->GetName(index), child_entry);
    1578             :   }
    1579             :   MarkVisitedField(field_offset);
    1580             : }
    1581             : 
    1582     1891493 : void V8HeapExplorer::SetHiddenReference(HeapObject parent_obj,
    1583             :                                         HeapEntry* parent_entry, int index,
    1584             :                                         Object child_obj, int field_offset) {
    1585             :   DCHECK_EQ(parent_entry, GetEntry(parent_obj));
    1586     1891493 :   HeapEntry* child_entry = GetEntry(child_obj);
    1587     2883390 :   if (child_entry != nullptr && IsEssentialObject(child_obj) &&
    1588      991897 :       IsEssentialHiddenReference(parent_obj, field_offset)) {
    1589             :     parent_entry->SetIndexedReference(HeapGraphEdge::kHidden, index,
    1590             :                                       child_entry);
    1591             :   }
    1592     1891493 : }
    1593             : 
    1594         979 : void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry,
    1595             :                                       const char* reference_name,
    1596             :                                       Object child_obj, int field_offset) {
    1597         979 :   HeapEntry* child_entry = GetEntry(child_obj);
    1598        1958 :   if (child_entry == nullptr) return;
    1599         979 :   if (IsEssentialObject(child_obj)) {
    1600             :     parent_entry->SetNamedReference(HeapGraphEdge::kWeak, reference_name,
    1601             :                                     child_entry);
    1602             :   }
    1603             :   MarkVisitedField(field_offset);
    1604             : }
    1605             : 
    1606      293138 : void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry, int index,
    1607             :                                       Object child_obj, int field_offset) {
    1608      293138 :   HeapEntry* child_entry = GetEntry(child_obj);
    1609      586276 :   if (child_entry == nullptr) return;
    1610      293138 :   if (IsEssentialObject(child_obj)) {
    1611             :     parent_entry->SetNamedReference(
    1612      293048 :         HeapGraphEdge::kWeak, names_->GetFormatted("%d", index), child_entry);
    1613             :   }
    1614             :   MarkVisitedField(field_offset);
    1615             : }
    1616             : 
    1617     1011580 : void V8HeapExplorer::SetDataOrAccessorPropertyReference(
    1618             :     PropertyKind kind, HeapEntry* parent_entry, Name reference_name,
    1619             :     Object child_obj, const char* name_format_string, int field_offset) {
    1620     1011580 :   if (kind == kAccessor) {
    1621             :     ExtractAccessorPairProperty(parent_entry, reference_name, child_obj,
    1622      723155 :                                 field_offset);
    1623             :   } else {
    1624             :     SetPropertyReference(parent_entry, reference_name, child_obj,
    1625      288425 :                          name_format_string, field_offset);
    1626             :   }
    1627     1011580 : }
    1628             : 
    1629      798848 : void V8HeapExplorer::SetPropertyReference(HeapEntry* parent_entry,
    1630             :                                           Name reference_name, Object child_obj,
    1631             :                                           const char* name_format_string,
    1632             :                                           int field_offset) {
    1633      798848 :   HeapEntry* child_entry = GetEntry(child_obj);
    1634     1597696 :   if (child_entry == nullptr) return;
    1635             :   HeapGraphEdge::Type type =
    1636      765437 :       reference_name->IsSymbol() || String::cast(reference_name)->length() > 0
    1637             :           ? HeapGraphEdge::kProperty
    1638      793306 :           : HeapGraphEdge::kInternal;
    1639             :   const char* name =
    1640       33493 :       name_format_string != nullptr && reference_name->IsString()
    1641             :           ? names_->GetFormatted(
    1642             :                 name_format_string,
    1643             :                 String::cast(reference_name)
    1644             :                     ->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)
    1645      913130 :                     .get())
    1646     1586612 :           : names_->GetName(reference_name);
    1647             : 
    1648             :   parent_entry->SetNamedReference(type, name, child_entry);
    1649             :   MarkVisitedField(field_offset);
    1650             : }
    1651             : 
    1652           0 : void V8HeapExplorer::SetRootGcRootsReference() {
    1653             :   snapshot_->root()->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
    1654         398 :                                                   snapshot_->gc_roots());
    1655           0 : }
    1656             : 
    1657         398 : void V8HeapExplorer::SetUserGlobalReference(Object child_obj) {
    1658         398 :   HeapEntry* child_entry = GetEntry(child_obj);
    1659             :   DCHECK_NOT_NULL(child_entry);
    1660             :   snapshot_->root()->SetNamedAutoIndexReference(HeapGraphEdge::kShortcut,
    1661         398 :                                                 nullptr, child_entry, names_);
    1662         398 : }
    1663             : 
    1664           0 : void V8HeapExplorer::SetGcRootsReference(Root root) {
    1665             :   snapshot_->gc_roots()->SetIndexedAutoIndexReference(
    1666       19104 :       HeapGraphEdge::kElement, snapshot_->gc_subroot(root));
    1667           0 : }
    1668             : 
    1669     1447794 : void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description,
    1670             :                                            bool is_weak, Object child_obj) {
    1671     1447794 :   HeapEntry* child_entry = GetEntry(child_obj);
    1672     2895190 :   if (child_entry == nullptr) return;
    1673     1444723 :   const char* name = GetStrongGcSubrootName(child_obj);
    1674             :   HeapGraphEdge::Type edge_type =
    1675     1444723 :       is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kInternal;
    1676     1444723 :   if (name != nullptr) {
    1677             :     snapshot_->gc_subroot(root)->SetNamedReference(edge_type, name,
    1678      236286 :                                                    child_entry);
    1679             :   } else {
    1680             :     snapshot_->gc_subroot(root)->SetNamedAutoIndexReference(
    1681     2416874 :         edge_type, description, child_entry, names_);
    1682             :   }
    1683             : 
    1684             :   // Add a shortcut to JS global object reference at snapshot root.
    1685             :   // That allows the user to easily find global objects. They are
    1686             :   // also used as starting points in distance calculations.
    1687     2889416 :   if (is_weak || !child_obj->IsNativeContext()) return;
    1688             : 
    1689        1952 :   JSGlobalObject global = Context::cast(child_obj)->global_object();
    1690        1952 :   if (!global->IsJSGlobalObject()) return;
    1691             : 
    1692        1952 :   if (!user_roots_.insert(global).second) return;
    1693             : 
    1694         398 :   SetUserGlobalReference(global);
    1695             : }
    1696             : 
    1697     1444723 : const char* V8HeapExplorer::GetStrongGcSubrootName(Object object) {
    1698     1444723 :   if (strong_gc_subroot_names_.empty()) {
    1699         398 :     Isolate* isolate = Isolate::FromHeap(heap_);
    1700      232830 :     for (RootIndex root_index = RootIndex::kFirstStrongOrReadOnlyRoot;
    1701             :          root_index <= RootIndex::kLastStrongOrReadOnlyRoot; ++root_index) {
    1702      232034 :       const char* name = RootsTable::name(root_index);
    1703      464068 :       strong_gc_subroot_names_.emplace(isolate->root(root_index), name);
    1704             :     }
    1705         398 :     CHECK(!strong_gc_subroot_names_.empty());
    1706             :   }
    1707             :   auto it = strong_gc_subroot_names_.find(object);
    1708     1444723 :   return it != strong_gc_subroot_names_.end() ? it->second : nullptr;
    1709             : }
    1710             : 
    1711     4698390 : void V8HeapExplorer::TagObject(Object obj, const char* tag) {
    1712     4698390 :   if (IsEssentialObject(obj)) {
    1713     2514694 :     HeapEntry* entry = GetEntry(obj);
    1714     2514694 :     if (entry->name()[0] == '\0') {
    1715             :       entry->set_name(tag);
    1716             :     }
    1717             :   }
    1718     4698390 : }
    1719             : 
    1720         796 : class GlobalObjectsEnumerator : public RootVisitor {
    1721             :  public:
    1722         603 :   void VisitRootPointers(Root root, const char* description,
    1723             :                          FullObjectSlot start, FullObjectSlot end) override {
    1724        1809 :     for (FullObjectSlot p = start; p < end; ++p) {
    1725        1386 :       if (!(*p)->IsNativeContext()) continue;
    1726         423 :       JSObject proxy = Context::cast(*p)->global_proxy();
    1727         423 :       if (!proxy->IsJSGlobalProxy()) continue;
    1728         423 :       Object global = proxy->map()->prototype();
    1729         423 :       if (!global->IsJSGlobalObject()) continue;
    1730             :       objects_.push_back(Handle<JSGlobalObject>(JSGlobalObject::cast(global),
    1731         846 :                                                 proxy->GetIsolate()));
    1732             :     }
    1733         603 :   }
    1734        2388 :   int count() const { return static_cast<int>(objects_.size()); }
    1735         110 :   Handle<JSGlobalObject>& at(int i) { return objects_[i]; }
    1736             : 
    1737             :  private:
    1738             :   std::vector<Handle<JSGlobalObject>> objects_;
    1739             : };
    1740             : 
    1741             : 
    1742             : // Modifies heap. Must not be run during heap traversal.
    1743         398 : void V8HeapExplorer::TagGlobalObjects() {
    1744         796 :   Isolate* isolate = Isolate::FromHeap(heap_);
    1745             :   HandleScope scope(isolate);
    1746             :   GlobalObjectsEnumerator enumerator;
    1747         398 :   isolate->global_handles()->IterateAllRoots(&enumerator);
    1748         398 :   std::vector<const char*> urls(enumerator.count());
    1749         821 :   for (int i = 0, l = enumerator.count(); i < l; ++i) {
    1750         423 :     urls[i] = global_object_name_resolver_
    1751             :                   ? global_object_name_resolver_->GetName(Utils::ToLocal(
    1752         110 :                         Handle<JSObject>::cast(enumerator.at(i))))
    1753         478 :                   : nullptr;
    1754             :   }
    1755             : 
    1756             :   DisallowHeapAllocation no_allocation;
    1757         821 :   for (int i = 0, l = enumerator.count(); i < l; ++i) {
    1758         956 :     if (urls[i]) objects_tags_.emplace(*enumerator.at(i), urls[i]);
    1759             :   }
    1760         398 : }
    1761             : 
    1762         140 : class EmbedderGraphImpl : public EmbedderGraph {
    1763             :  public:
    1764             :   struct Edge {
    1765             :     Node* from;
    1766             :     Node* to;
    1767             :     const char* name;
    1768             :   };
    1769             : 
    1770         100 :   class V8NodeImpl : public Node {
    1771             :    public:
    1772          50 :     explicit V8NodeImpl(Object object) : object_(object) {}
    1773             :     Object GetObject() { return object_; }
    1774             : 
    1775             :     // Node overrides.
    1776          75 :     bool IsEmbedderNode() override { return false; }
    1777           0 :     const char* Name() override {
    1778             :       // The name should be retrieved via GetObject().
    1779           0 :       UNREACHABLE();
    1780             :       return "";
    1781             :     }
    1782           0 :     size_t SizeInBytes() override {
    1783             :       // The size should be retrieved via GetObject().
    1784           0 :       UNREACHABLE();
    1785             :       return 0;
    1786             :     }
    1787             : 
    1788             :    private:
    1789             :     Object object_;
    1790             :   };
    1791             : 
    1792          50 :   Node* V8Node(const v8::Local<v8::Value>& value) final {
    1793             :     Handle<Object> object = v8::Utils::OpenHandle(*value);
    1794             :     DCHECK(!object.is_null());
    1795         100 :     return AddNode(std::unique_ptr<Node>(new V8NodeImpl(*object)));
    1796             :   }
    1797             : 
    1798          90 :   Node* AddNode(std::unique_ptr<Node> node) final {
    1799             :     Node* result = node.get();
    1800         140 :     nodes_.push_back(std::move(node));
    1801          90 :     return result;
    1802             :   }
    1803             : 
    1804         110 :   void AddEdge(Node* from, Node* to, const char* name) final {
    1805         220 :     edges_.push_back({from, to, name});
    1806         110 :   }
    1807             : 
    1808             :   const std::vector<std::unique_ptr<Node>>& nodes() { return nodes_; }
    1809             :   const std::vector<Edge>& edges() { return edges_; }
    1810             : 
    1811             :  private:
    1812             :   std::vector<std::unique_ptr<Node>> nodes_;
    1813             :   std::vector<Edge> edges_;
    1814             : };
    1815             : 
    1816         796 : class EmbedderGraphEntriesAllocator : public HeapEntriesAllocator {
    1817             :  public:
    1818             :   explicit EmbedderGraphEntriesAllocator(HeapSnapshot* snapshot)
    1819             :       : snapshot_(snapshot),
    1820         796 :         names_(snapshot_->profiler()->names()),
    1821        1194 :         heap_object_map_(snapshot_->profiler()->heap_object_map()) {}
    1822             :   HeapEntry* AllocateEntry(HeapThing ptr) override;
    1823             : 
    1824             :  private:
    1825             :   HeapSnapshot* snapshot_;
    1826             :   StringsStorage* names_;
    1827             :   HeapObjectsMap* heap_object_map_;
    1828             : };
    1829             : 
    1830             : namespace {
    1831             : 
    1832          90 : const char* EmbedderGraphNodeName(StringsStorage* names,
    1833             :                                   EmbedderGraphImpl::Node* node) {
    1834          90 :   const char* prefix = node->NamePrefix();
    1835           5 :   return prefix ? names->GetFormatted("%s %s", prefix, node->Name())
    1836          95 :                 : names->GetCopy(node->Name());
    1837             : }
    1838             : 
    1839             : HeapEntry::Type EmbedderGraphNodeType(EmbedderGraphImpl::Node* node) {
    1840             :   return HeapEntry::kNative;
    1841             : }
    1842             : 
    1843             : // Merges the names of an embedder node and its wrapper node.
    1844             : // If the wrapper node name contains a tag suffix (part after '/') then the
    1845             : // result is the embedder node name concatenated with the tag suffix.
    1846             : // Otherwise, the result is the embedder node name.
    1847          10 : const char* MergeNames(StringsStorage* names, const char* embedder_name,
    1848             :                        const char* wrapper_name) {
    1849             :   const char* suffix = strchr(wrapper_name, '/');
    1850             :   return suffix ? names->GetFormatted("%s %s", embedder_name, suffix)
    1851          10 :                 : embedder_name;
    1852             : }
    1853             : 
    1854             : }  // anonymous namespace
    1855             : 
    1856          80 : HeapEntry* EmbedderGraphEntriesAllocator::AllocateEntry(HeapThing ptr) {
    1857             :   EmbedderGraphImpl::Node* node =
    1858             :       reinterpret_cast<EmbedderGraphImpl::Node*>(ptr);
    1859             :   DCHECK(node->IsEmbedderNode());
    1860          80 :   size_t size = node->SizeInBytes();
    1861             :   return snapshot_->AddEntry(
    1862             :       EmbedderGraphNodeType(node), EmbedderGraphNodeName(names_, node),
    1863             :       static_cast<SnapshotObjectId>(reinterpret_cast<uintptr_t>(node) << 1),
    1864          80 :       static_cast<int>(size), 0);
    1865             : }
    1866             : 
    1867         398 : NativeObjectsExplorer::NativeObjectsExplorer(
    1868         398 :     HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress)
    1869             :     : isolate_(
    1870         398 :           Isolate::FromHeap(snapshot->profiler()->heap_object_map()->heap())),
    1871             :       snapshot_(snapshot),
    1872         398 :       names_(snapshot_->profiler()->names()),
    1873             :       embedder_graph_entries_allocator_(
    1874        1194 :           new EmbedderGraphEntriesAllocator(snapshot)) {}
    1875             : 
    1876         245 : HeapEntry* NativeObjectsExplorer::EntryForEmbedderGraphNode(
    1877             :     EmbedderGraphImpl::Node* node) {
    1878         245 :   EmbedderGraphImpl::Node* wrapper = node->WrapperNode();
    1879         245 :   if (wrapper) {
    1880             :     node = wrapper;
    1881             :   }
    1882         245 :   if (node->IsEmbedderNode()) {
    1883             :     return generator_->FindOrAddEntry(node,
    1884         170 :                                       embedder_graph_entries_allocator_.get());
    1885             :   } else {
    1886             :     EmbedderGraphImpl::V8NodeImpl* v8_node =
    1887             :         static_cast<EmbedderGraphImpl::V8NodeImpl*>(node);
    1888          75 :     Object object = v8_node->GetObject();
    1889          75 :     if (object->IsSmi()) return nullptr;
    1890             :     return generator_->FindEntry(
    1891          75 :         reinterpret_cast<void*>(Object::cast(object).ptr()));
    1892             :   }
    1893             : }
    1894             : 
    1895         393 : bool NativeObjectsExplorer::IterateAndExtractReferences(
    1896             :     HeapSnapshotGenerator* generator) {
    1897         393 :   generator_ = generator;
    1898             : 
    1899         786 :   if (FLAG_heap_profiler_use_embedder_graph &&
    1900         443 :       snapshot_->profiler()->HasBuildEmbedderGraphCallback()) {
    1901          35 :     v8::HandleScope scope(reinterpret_cast<v8::Isolate*>(isolate_));
    1902             :     DisallowHeapAllocation no_allocation;
    1903          35 :     EmbedderGraphImpl graph;
    1904          70 :     snapshot_->profiler()->BuildEmbedderGraph(isolate_, &graph);
    1905         210 :     for (const auto& node : graph.nodes()) {
    1906         140 :       if (node->IsRootNode()) {
    1907             :         snapshot_->root()->SetIndexedAutoIndexReference(
    1908          30 :             HeapGraphEdge::kElement, EntryForEmbedderGraphNode(node.get()));
    1909             :       }
    1910             :       // Adjust the name and the type of the V8 wrapper node.
    1911         140 :       auto wrapper = node->WrapperNode();
    1912         140 :       if (wrapper) {
    1913          10 :         HeapEntry* wrapper_entry = EntryForEmbedderGraphNode(wrapper);
    1914             :         wrapper_entry->set_name(
    1915             :             MergeNames(names_, EmbedderGraphNodeName(names_, node.get()),
    1916          10 :                        wrapper_entry->name()));
    1917             :         wrapper_entry->set_type(EmbedderGraphNodeType(node.get()));
    1918             :       }
    1919             :     }
    1920             :     // Fill edges of the graph.
    1921         180 :     for (const auto& edge : graph.edges()) {
    1922         110 :       HeapEntry* from = EntryForEmbedderGraphNode(edge.from);
    1923             :       // |from| and |to| can be nullptr if the corresponding node is a V8 node
    1924             :       // pointing to a Smi.
    1925         110 :       if (!from) continue;
    1926         110 :       HeapEntry* to = EntryForEmbedderGraphNode(edge.to);
    1927         110 :       if (!to) continue;
    1928         110 :       if (edge.name == nullptr) {
    1929         100 :         from->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, to);
    1930             :       } else {
    1931             :         from->SetNamedReference(HeapGraphEdge::kInternal, edge.name, to);
    1932             :       }
    1933          35 :     }
    1934             :   }
    1935         393 :   generator_ = nullptr;
    1936         393 :   return true;
    1937             : }
    1938             : 
    1939         398 : HeapSnapshotGenerator::HeapSnapshotGenerator(
    1940             :     HeapSnapshot* snapshot,
    1941             :     v8::ActivityControl* control,
    1942             :     v8::HeapProfiler::ObjectNameResolver* resolver,
    1943             :     Heap* heap)
    1944             :     : snapshot_(snapshot),
    1945             :       control_(control),
    1946             :       v8_heap_explorer_(snapshot_, this, resolver),
    1947             :       dom_explorer_(snapshot_, this),
    1948         796 :       heap_(heap) {
    1949         398 : }
    1950             : 
    1951             : namespace {
    1952             : class NullContextScope {
    1953             :  public:
    1954             :   explicit NullContextScope(Isolate* isolate)
    1955             :       : isolate_(isolate), prev_(isolate->context()) {
    1956             :     isolate_->set_context(Context());
    1957             :   }
    1958             :   ~NullContextScope() { isolate_->set_context(prev_); }
    1959             : 
    1960             :  private:
    1961             :   Isolate* isolate_;
    1962             :   Context prev_;
    1963             : };
    1964             : }  //  namespace
    1965             : 
    1966         398 : bool HeapSnapshotGenerator::GenerateSnapshot() {
    1967         398 :   v8_heap_explorer_.TagGlobalObjects();
    1968             : 
    1969             :   // TODO(1562) Profiler assumes that any object that is in the heap after
    1970             :   // full GC is reachable from the root when computing dominators.
    1971             :   // This is not true for weakly reachable objects.
    1972             :   // As a temporary solution we call GC twice.
    1973             :   heap_->PreciseCollectAllGarbage(Heap::kNoGCFlags,
    1974         398 :                                   GarbageCollectionReason::kHeapProfiler);
    1975             :   heap_->PreciseCollectAllGarbage(Heap::kNoGCFlags,
    1976         398 :                                   GarbageCollectionReason::kHeapProfiler);
    1977             : 
    1978         398 :   NullContextScope null_context_scope(Isolate::FromHeap(heap_));
    1979             : 
    1980             : #ifdef VERIFY_HEAP
    1981             :   Heap* debug_heap = heap_;
    1982             :   if (FLAG_verify_heap) {
    1983             :     debug_heap->Verify();
    1984             :   }
    1985             : #endif
    1986             : 
    1987         398 :   InitProgressCounter();
    1988             : 
    1989             : #ifdef VERIFY_HEAP
    1990             :   if (FLAG_verify_heap) {
    1991             :     debug_heap->Verify();
    1992             :   }
    1993             : #endif
    1994             : 
    1995         398 :   snapshot_->AddSyntheticRootEntries();
    1996             : 
    1997         398 :   if (!FillReferences()) return false;
    1998             : 
    1999         393 :   snapshot_->FillChildren();
    2000         393 :   snapshot_->RememberLastJSObjectId();
    2001             : 
    2002         393 :   progress_counter_ = progress_total_;
    2003         393 :   if (!ProgressReport(true)) return false;
    2004         393 :   return true;
    2005             : }
    2006             : 
    2007     3024091 : void HeapSnapshotGenerator::ProgressStep() {
    2008     3024091 :   ++progress_counter_;
    2009     3024091 : }
    2010             : 
    2011     2992578 : bool HeapSnapshotGenerator::ProgressReport(bool force) {
    2012             :   const int kProgressReportGranularity = 10000;
    2013     2992578 :   if (control_ != nullptr &&
    2014       64613 :       (force || progress_counter_ % kProgressReportGranularity == 0)) {
    2015          35 :     return control_->ReportProgressValue(progress_counter_, progress_total_) ==
    2016          35 :            v8::ActivityControl::kContinue;
    2017             :   }
    2018             :   return true;
    2019             : }
    2020             : 
    2021         398 : void HeapSnapshotGenerator::InitProgressCounter() {
    2022         796 :   if (control_ == nullptr) return;
    2023             :   // The +1 ensures that intermediate ProgressReport calls will never signal
    2024             :   // that the work is finished (i.e. progress_counter_ == progress_total_).
    2025             :   // Only the forced ProgressReport() at the end of GenerateSnapshot()
    2026             :   // should signal that the work is finished because signalling finished twice
    2027             :   // breaks the DevTools frontend.
    2028          15 :   progress_total_ = v8_heap_explorer_.EstimateObjectsCount() + 1;
    2029          15 :   progress_counter_ = 0;
    2030             : }
    2031             : 
    2032         398 : bool HeapSnapshotGenerator::FillReferences() {
    2033         791 :   return v8_heap_explorer_.IterateAndExtractReferences(this) &&
    2034         791 :          dom_explorer_.IterateAndExtractReferences(this);
    2035             : }
    2036             : 
    2037             : template<int bytes> struct MaxDecimalDigitsIn;
    2038             : template<> struct MaxDecimalDigitsIn<4> {
    2039             :   static const int kSigned = 11;
    2040             :   static const int kUnsigned = 10;
    2041             : };
    2042             : template<> struct MaxDecimalDigitsIn<8> {
    2043             :   static const int kSigned = 20;
    2044             :   static const int kUnsigned = 20;
    2045             : };
    2046             : 
    2047             : class OutputStreamWriter {
    2048             :  public:
    2049          35 :   explicit OutputStreamWriter(v8::OutputStream* stream)
    2050             :       : stream_(stream),
    2051          35 :         chunk_size_(stream->GetChunkSize()),
    2052             :         chunk_(chunk_size_),
    2053             :         chunk_pos_(0),
    2054         105 :         aborted_(false) {
    2055             :     DCHECK_GT(chunk_size_, 0);
    2056          35 :   }
    2057             :   bool aborted() { return aborted_; }
    2058     4778129 :   void AddCharacter(char c) {
    2059             :     DCHECK_NE(c, '\0');
    2060             :     DCHECK(chunk_pos_ < chunk_size_);
    2061     9556258 :     chunk_[chunk_pos_++] = c;
    2062             :     MaybeWriteChunk();
    2063     4778129 :   }
    2064      956796 :   void AddString(const char* s) {
    2065      956796 :     AddSubstring(s, StrLength(s));
    2066      956796 :   }
    2067      956796 :   void AddSubstring(const char* s, int n) {
    2068     1913592 :     if (n <= 0) return;
    2069             :     DCHECK(static_cast<size_t>(n) <= strlen(s));
    2070      956796 :     const char* s_end = s + n;
    2071     2872465 :     while (s < s_end) {
    2072             :       int s_chunk_size =
    2073      958873 :           Min(chunk_size_ - chunk_pos_, static_cast<int>(s_end - s));
    2074             :       DCHECK_GT(s_chunk_size, 0);
    2075      958873 :       MemCopy(chunk_.start() + chunk_pos_, s, s_chunk_size);
    2076      958873 :       s += s_chunk_size;
    2077      958873 :       chunk_pos_ += s_chunk_size;
    2078             :       MaybeWriteChunk();
    2079             :     }
    2080             :   }
    2081         105 :   void AddNumber(unsigned n) { AddNumberImpl<unsigned>(n, "%u"); }
    2082          30 :   void Finalize() {
    2083          60 :     if (aborted_) return;
    2084             :     DCHECK(chunk_pos_ < chunk_size_);
    2085          30 :     if (chunk_pos_ != 0) {
    2086          30 :       WriteChunk();
    2087             :     }
    2088          30 :     stream_->EndOfStream();
    2089             :   }
    2090             : 
    2091             :  private:
    2092             :   template<typename T>
    2093         105 :   void AddNumberImpl(T n, const char* format) {
    2094             :     // Buffer for the longest value plus trailing \0
    2095             :     static const int kMaxNumberSize =
    2096             :         MaxDecimalDigitsIn<sizeof(T)>::kUnsigned + 1;
    2097         105 :     if (chunk_size_ - chunk_pos_ >= kMaxNumberSize) {
    2098             :       int result = SNPrintF(
    2099         210 :           chunk_.SubVector(chunk_pos_, chunk_size_), format, n);
    2100             :       DCHECK_NE(result, -1);
    2101         105 :       chunk_pos_ += result;
    2102             :       MaybeWriteChunk();
    2103             :     } else {
    2104             :       EmbeddedVector<char, kMaxNumberSize> buffer;
    2105           0 :       int result = SNPrintF(buffer, format, n);
    2106             :       USE(result);
    2107             :       DCHECK_NE(result, -1);
    2108           0 :       AddString(buffer.start());
    2109             :     }
    2110         105 :   }
    2111             :   void MaybeWriteChunk() {
    2112             :     DCHECK(chunk_pos_ <= chunk_size_);
    2113     5737107 :     if (chunk_pos_ == chunk_size_) {
    2114        3079 :       WriteChunk();
    2115             :     }
    2116             :   }
    2117        3109 :   void WriteChunk() {
    2118        6218 :     if (aborted_) return;
    2119        3109 :     if (stream_->WriteAsciiChunk(chunk_.start(), chunk_pos_) ==
    2120           5 :         v8::OutputStream::kAbort) aborted_ = true;
    2121        3109 :     chunk_pos_ = 0;
    2122             :   }
    2123             : 
    2124             :   v8::OutputStream* stream_;
    2125             :   int chunk_size_;
    2126             :   ScopedVector<char> chunk_;
    2127             :   int chunk_pos_;
    2128             :   bool aborted_;
    2129             : };
    2130             : 
    2131             : 
    2132             : // type, name|index, to_node.
    2133             : const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3;
    2134             : // type, name, id, self_size, edge_count, trace_node_id.
    2135             : const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 6;
    2136             : 
    2137          35 : void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
    2138          35 :   if (AllocationTracker* allocation_tracker =
    2139          35 :       snapshot_->profiler()->allocation_tracker()) {
    2140           0 :     allocation_tracker->PrepareForSerialization();
    2141             :   }
    2142             :   DCHECK_NULL(writer_);
    2143          35 :   writer_ = new OutputStreamWriter(stream);
    2144          35 :   SerializeImpl();
    2145          70 :   delete writer_;
    2146          35 :   writer_ = nullptr;
    2147          35 : }
    2148             : 
    2149             : 
    2150          35 : void HeapSnapshotJSONSerializer::SerializeImpl() {
    2151             :   DCHECK_EQ(0, snapshot_->root()->index());
    2152         285 :   writer_->AddCharacter('{');
    2153          35 :   writer_->AddString("\"snapshot\":{");
    2154          35 :   SerializeSnapshot();
    2155          70 :   if (writer_->aborted()) return;
    2156          35 :   writer_->AddString("},\n");
    2157          35 :   writer_->AddString("\"nodes\":[");
    2158          35 :   SerializeNodes();
    2159          70 :   if (writer_->aborted()) return;
    2160          30 :   writer_->AddString("],\n");
    2161          30 :   writer_->AddString("\"edges\":[");
    2162          30 :   SerializeEdges();
    2163          60 :   if (writer_->aborted()) return;
    2164          30 :   writer_->AddString("],\n");
    2165             : 
    2166          30 :   writer_->AddString("\"trace_function_infos\":[");
    2167          30 :   SerializeTraceNodeInfos();
    2168          60 :   if (writer_->aborted()) return;
    2169          30 :   writer_->AddString("],\n");
    2170          30 :   writer_->AddString("\"trace_tree\":[");
    2171          30 :   SerializeTraceTree();
    2172          60 :   if (writer_->aborted()) return;
    2173          30 :   writer_->AddString("],\n");
    2174             : 
    2175          30 :   writer_->AddString("\"samples\":[");
    2176          30 :   SerializeSamples();
    2177          60 :   if (writer_->aborted()) return;
    2178          30 :   writer_->AddString("],\n");
    2179             : 
    2180          30 :   writer_->AddString("\"locations\":[");
    2181          30 :   SerializeLocations();
    2182          60 :   if (writer_->aborted()) return;
    2183          30 :   writer_->AddString("],\n");
    2184             : 
    2185          30 :   writer_->AddString("\"strings\":[");
    2186          30 :   SerializeStrings();
    2187          60 :   if (writer_->aborted()) return;
    2188          30 :   writer_->AddCharacter(']');
    2189          30 :   writer_->AddCharacter('}');
    2190          30 :   writer_->Finalize();
    2191             : }
    2192             : 
    2193             : 
    2194      876058 : int HeapSnapshotJSONSerializer::GetStringId(const char* s) {
    2195             :   base::HashMap::Entry* cache_entry =
    2196     1752116 :       strings_.LookupOrInsert(const_cast<char*>(s), StringHash(s));
    2197      876058 :   if (cache_entry->value == nullptr) {
    2198      199817 :     cache_entry->value = reinterpret_cast<void*>(next_string_id_++);
    2199             :   }
    2200      876058 :   return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value));
    2201             : }
    2202             : 
    2203             : 
    2204             : namespace {
    2205             : 
    2206             : template<size_t size> struct ToUnsigned;
    2207             : 
    2208             : template<> struct ToUnsigned<4> {
    2209             :   typedef uint32_t Type;
    2210             : };
    2211             : 
    2212             : template<> struct ToUnsigned<8> {
    2213             :   typedef uint64_t Type;
    2214             : };
    2215             : 
    2216             : }  // namespace
    2217             : 
    2218             : 
    2219             : template<typename T>
    2220     9132235 : static int utoa_impl(T value, const Vector<char>& buffer, int buffer_pos) {
    2221             :   STATIC_ASSERT(static_cast<T>(-1) > 0);  // Check that T is unsigned
    2222             :   int number_of_digits = 0;
    2223             :   T t = value;
    2224     9132235 :   do {
    2225     9132235 :     ++number_of_digits;
    2226             :   } while (t /= 10);
    2227             : 
    2228     3491187 :   buffer_pos += number_of_digits;
    2229             :   int result = buffer_pos;
    2230     9132235 :   do {
    2231     9132235 :     int last_digit = static_cast<int>(value % 10);
    2232    18264470 :     buffer[--buffer_pos] = '0' + last_digit;
    2233     9132235 :     value /= 10;
    2234             :   } while (value);
    2235             :   return result;
    2236             : }
    2237             : 
    2238             : 
    2239             : template<typename T>
    2240             : static int utoa(T value, const Vector<char>& buffer, int buffer_pos) {
    2241     1910832 :   typename ToUnsigned<sizeof(value)>::Type unsigned_value = value;
    2242             :   STATIC_ASSERT(sizeof(value) == sizeof(unsigned_value));
    2243             :   return utoa_impl(unsigned_value, buffer, buffer_pos);
    2244             : }
    2245             : 
    2246             : 
    2247     3730040 : void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
    2248             :                                                bool first_edge) {
    2249             :   // The buffer needs space for 3 unsigned ints, 3 commas, \n and \0
    2250             :   static const int kBufferSize =
    2251             :       MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned * 3 + 3 + 2;  // NOLINT
    2252             :   EmbeddedVector<char, kBufferSize> buffer;
    2253             :   int edge_name_or_index = edge->type() == HeapGraphEdge::kElement
    2254      745250 :       || edge->type() == HeapGraphEdge::kHidden
    2255     1492016 :       ? edge->index() : GetStringId(edge->name());
    2256             :   int buffer_pos = 0;
    2257      746008 :   if (!first_edge) {
    2258      745978 :     buffer[buffer_pos++] = ',';
    2259             :   }
    2260             :   buffer_pos = utoa(edge->type(), buffer, buffer_pos);
    2261     1492016 :   buffer[buffer_pos++] = ',';
    2262             :   buffer_pos = utoa(edge_name_or_index, buffer, buffer_pos);
    2263     1492016 :   buffer[buffer_pos++] = ',';
    2264             :   buffer_pos = utoa(to_node_index(edge->to()), buffer, buffer_pos);
    2265     1492016 :   buffer[buffer_pos++] = '\n';
    2266     1492016 :   buffer[buffer_pos++] = '\0';
    2267      746008 :   writer_->AddString(buffer.start());
    2268      746008 : }
    2269             : 
    2270          30 : void HeapSnapshotJSONSerializer::SerializeEdges() {
    2271      746068 :   std::vector<HeapGraphEdge*>& edges = snapshot_->children();
    2272     1492076 :   for (size_t i = 0; i < edges.size(); ++i) {
    2273             :     DCHECK(i == 0 ||
    2274             :            edges[i - 1]->from()->index() <= edges[i]->from()->index());
    2275     1492016 :     SerializeEdge(edges[i], i == 0);
    2276      746038 :     if (writer_->aborted()) return;
    2277             :   }
    2278             : }
    2279             : 
    2280     1043390 : void HeapSnapshotJSONSerializer::SerializeNode(const HeapEntry* entry) {
    2281             :   // The buffer needs space for 4 unsigned ints, 1 size_t, 5 commas, \n and \0
    2282             :   static const int kBufferSize =
    2283             :       5 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
    2284             :       + MaxDecimalDigitsIn<sizeof(size_t)>::kUnsigned  // NOLINT
    2285             :       + 6 + 1 + 1;
    2286             :   EmbeddedVector<char, kBufferSize> buffer;
    2287             :   int buffer_pos = 0;
    2288      208678 :   if (to_node_index(entry) != 0) {
    2289      208643 :     buffer[buffer_pos++] = ',';
    2290             :   }
    2291             :   buffer_pos = utoa(entry->type(), buffer, buffer_pos);
    2292      417356 :   buffer[buffer_pos++] = ',';
    2293      208678 :   buffer_pos = utoa(GetStringId(entry->name()), buffer, buffer_pos);
    2294      417356 :   buffer[buffer_pos++] = ',';
    2295             :   buffer_pos = utoa(entry->id(), buffer, buffer_pos);
    2296      417356 :   buffer[buffer_pos++] = ',';
    2297             :   buffer_pos = utoa(entry->self_size(), buffer, buffer_pos);
    2298      417356 :   buffer[buffer_pos++] = ',';
    2299             :   buffer_pos = utoa(entry->children_count(), buffer, buffer_pos);
    2300      417356 :   buffer[buffer_pos++] = ',';
    2301             :   buffer_pos = utoa(entry->trace_node_id(), buffer, buffer_pos);
    2302      417356 :   buffer[buffer_pos++] = '\n';
    2303      417356 :   buffer[buffer_pos++] = '\0';
    2304      208678 :   writer_->AddString(buffer.start());
    2305      208678 : }
    2306             : 
    2307          35 : void HeapSnapshotJSONSerializer::SerializeNodes() {
    2308          35 :   const std::deque<HeapEntry>& entries = snapshot_->entries();
    2309      208708 :   for (const HeapEntry& entry : entries) {
    2310      208678 :     SerializeNode(&entry);
    2311      208713 :     if (writer_->aborted()) return;
    2312             :   }
    2313             : }
    2314             : 
    2315          35 : void HeapSnapshotJSONSerializer::SerializeSnapshot() {
    2316          35 :   writer_->AddString("\"meta\":");
    2317             :   // The object describing node serialization layout.
    2318             :   // We use a set of macros to improve readability.
    2319             : 
    2320             : // clang-format off
    2321             : #define JSON_A(s) "[" s "]"
    2322             : #define JSON_O(s) "{" s "}"
    2323             : #define JSON_S(s) "\"" s "\""
    2324             :   writer_->AddString(JSON_O(
    2325             :     JSON_S("node_fields") ":" JSON_A(
    2326             :         JSON_S("type") ","
    2327             :         JSON_S("name") ","
    2328             :         JSON_S("id") ","
    2329             :         JSON_S("self_size") ","
    2330             :         JSON_S("edge_count") ","
    2331             :         JSON_S("trace_node_id")) ","
    2332             :     JSON_S("node_types") ":" JSON_A(
    2333             :         JSON_A(
    2334             :             JSON_S("hidden") ","
    2335             :             JSON_S("array") ","
    2336             :             JSON_S("string") ","
    2337             :             JSON_S("object") ","
    2338             :             JSON_S("code") ","
    2339             :             JSON_S("closure") ","
    2340             :             JSON_S("regexp") ","
    2341             :             JSON_S("number") ","
    2342             :             JSON_S("native") ","
    2343             :             JSON_S("synthetic") ","
    2344             :             JSON_S("concatenated string") ","
    2345             :             JSON_S("sliced string") ","
    2346             :             JSON_S("symbol") ","
    2347             :             JSON_S("bigint")) ","
    2348             :         JSON_S("string") ","
    2349             :         JSON_S("number") ","
    2350             :         JSON_S("number") ","
    2351             :         JSON_S("number") ","
    2352             :         JSON_S("number") ","
    2353             :         JSON_S("number")) ","
    2354             :     JSON_S("edge_fields") ":" JSON_A(
    2355             :         JSON_S("type") ","
    2356             :         JSON_S("name_or_index") ","
    2357             :         JSON_S("to_node")) ","
    2358             :     JSON_S("edge_types") ":" JSON_A(
    2359             :         JSON_A(
    2360             :             JSON_S("context") ","
    2361             :             JSON_S("element") ","
    2362             :             JSON_S("property") ","
    2363             :             JSON_S("internal") ","
    2364             :             JSON_S("hidden") ","
    2365             :             JSON_S("shortcut") ","
    2366             :             JSON_S("weak")) ","
    2367             :         JSON_S("string_or_number") ","
    2368             :         JSON_S("node")) ","
    2369             :     JSON_S("trace_function_info_fields") ":" JSON_A(
    2370             :         JSON_S("function_id") ","
    2371             :         JSON_S("name") ","
    2372             :         JSON_S("script_name") ","
    2373             :         JSON_S("script_id") ","
    2374             :         JSON_S("line") ","
    2375             :         JSON_S("column")) ","
    2376             :     JSON_S("trace_node_fields") ":" JSON_A(
    2377             :         JSON_S("id") ","
    2378             :         JSON_S("function_info_index") ","
    2379             :         JSON_S("count") ","
    2380             :         JSON_S("size") ","
    2381             :         JSON_S("children")) ","
    2382             :     JSON_S("sample_fields") ":" JSON_A(
    2383             :         JSON_S("timestamp_us") ","
    2384             :         JSON_S("last_assigned_id")) ","
    2385             :     JSON_S("location_fields") ":" JSON_A(
    2386             :         JSON_S("object_index") ","
    2387             :         JSON_S("script_id") ","
    2388             :         JSON_S("line") ","
    2389          35 :         JSON_S("column"))));
    2390             : // clang-format on
    2391             : #undef JSON_S
    2392             : #undef JSON_O
    2393             : #undef JSON_A
    2394          35 :   writer_->AddString(",\"node_count\":");
    2395         105 :   writer_->AddNumber(static_cast<unsigned>(snapshot_->entries().size()));
    2396          35 :   writer_->AddString(",\"edge_count\":");
    2397          70 :   writer_->AddNumber(static_cast<double>(snapshot_->edges().size()));
    2398          35 :   writer_->AddString(",\"trace_function_count\":");
    2399             :   uint32_t count = 0;
    2400          35 :   AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker();
    2401          35 :   if (tracker) {
    2402           0 :     count = static_cast<uint32_t>(tracker->function_info_list().size());
    2403             :   }
    2404          35 :   writer_->AddNumber(count);
    2405          35 : }
    2406             : 
    2407             : 
    2408          20 : static void WriteUChar(OutputStreamWriter* w, unibrow::uchar u) {
    2409             :   static const char hex_chars[] = "0123456789ABCDEF";
    2410          20 :   w->AddString("\\u");
    2411          20 :   w->AddCharacter(hex_chars[(u >> 12) & 0xF]);
    2412          20 :   w->AddCharacter(hex_chars[(u >> 8) & 0xF]);
    2413          20 :   w->AddCharacter(hex_chars[(u >> 4) & 0xF]);
    2414          20 :   w->AddCharacter(hex_chars[u & 0xF]);
    2415          20 : }
    2416             : 
    2417             : 
    2418          30 : void HeapSnapshotJSONSerializer::SerializeTraceTree() {
    2419          30 :   AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker();
    2420          60 :   if (!tracker) return;
    2421             :   AllocationTraceTree* traces = tracker->trace_tree();
    2422           0 :   SerializeTraceNode(traces->root());
    2423             : }
    2424             : 
    2425             : 
    2426           0 : void HeapSnapshotJSONSerializer::SerializeTraceNode(AllocationTraceNode* node) {
    2427             :   // The buffer needs space for 4 unsigned ints, 4 commas, [ and \0
    2428             :   const int kBufferSize =
    2429             :       4 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
    2430             :       + 4 + 1 + 1;
    2431             :   EmbeddedVector<char, kBufferSize> buffer;
    2432             :   int buffer_pos = 0;
    2433             :   buffer_pos = utoa(node->id(), buffer, buffer_pos);
    2434           0 :   buffer[buffer_pos++] = ',';
    2435             :   buffer_pos = utoa(node->function_info_index(), buffer, buffer_pos);
    2436           0 :   buffer[buffer_pos++] = ',';
    2437             :   buffer_pos = utoa(node->allocation_count(), buffer, buffer_pos);
    2438           0 :   buffer[buffer_pos++] = ',';
    2439             :   buffer_pos = utoa(node->allocation_size(), buffer, buffer_pos);
    2440           0 :   buffer[buffer_pos++] = ',';
    2441           0 :   buffer[buffer_pos++] = '[';
    2442           0 :   buffer[buffer_pos++] = '\0';
    2443           0 :   writer_->AddString(buffer.start());
    2444             : 
    2445             :   int i = 0;
    2446           0 :   for (AllocationTraceNode* child : node->children()) {
    2447           0 :     if (i++ > 0) {
    2448           0 :       writer_->AddCharacter(',');
    2449             :     }
    2450           0 :     SerializeTraceNode(child);
    2451             :   }
    2452           0 :   writer_->AddCharacter(']');
    2453           0 : }
    2454             : 
    2455             : 
    2456             : // 0-based position is converted to 1-based during the serialization.
    2457           0 : static int SerializePosition(int position, const Vector<char>& buffer,
    2458             :                              int buffer_pos) {
    2459           0 :   if (position == -1) {
    2460           0 :     buffer[buffer_pos++] = '0';
    2461             :   } else {
    2462             :     DCHECK_GE(position, 0);
    2463           0 :     buffer_pos = utoa(static_cast<unsigned>(position + 1), buffer, buffer_pos);
    2464             :   }
    2465           0 :   return buffer_pos;
    2466             : }
    2467             : 
    2468             : 
    2469          30 : void HeapSnapshotJSONSerializer::SerializeTraceNodeInfos() {
    2470          30 :   AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker();
    2471          60 :   if (!tracker) return;
    2472             :   // The buffer needs space for 6 unsigned ints, 6 commas, \n and \0
    2473             :   const int kBufferSize =
    2474             :       6 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
    2475             :       + 6 + 1 + 1;
    2476             :   EmbeddedVector<char, kBufferSize> buffer;
    2477             :   int i = 0;
    2478           0 :   for (AllocationTracker::FunctionInfo* info : tracker->function_info_list()) {
    2479             :     int buffer_pos = 0;
    2480           0 :     if (i++ > 0) {
    2481           0 :       buffer[buffer_pos++] = ',';
    2482             :     }
    2483           0 :     buffer_pos = utoa(info->function_id, buffer, buffer_pos);
    2484           0 :     buffer[buffer_pos++] = ',';
    2485           0 :     buffer_pos = utoa(GetStringId(info->name), buffer, buffer_pos);
    2486           0 :     buffer[buffer_pos++] = ',';
    2487           0 :     buffer_pos = utoa(GetStringId(info->script_name), buffer, buffer_pos);
    2488           0 :     buffer[buffer_pos++] = ',';
    2489             :     // The cast is safe because script id is a non-negative Smi.
    2490             :     buffer_pos = utoa(static_cast<unsigned>(info->script_id), buffer,
    2491           0 :         buffer_pos);
    2492           0 :     buffer[buffer_pos++] = ',';
    2493           0 :     buffer_pos = SerializePosition(info->line, buffer, buffer_pos);
    2494           0 :     buffer[buffer_pos++] = ',';
    2495           0 :     buffer_pos = SerializePosition(info->column, buffer, buffer_pos);
    2496           0 :     buffer[buffer_pos++] = '\n';
    2497           0 :     buffer[buffer_pos++] = '\0';
    2498           0 :     writer_->AddString(buffer.start());
    2499             :   }
    2500             : }
    2501             : 
    2502             : 
    2503          30 : void HeapSnapshotJSONSerializer::SerializeSamples() {
    2504             :   const std::vector<HeapObjectsMap::TimeInterval>& samples =
    2505          30 :       snapshot_->profiler()->heap_object_map()->samples();
    2506          60 :   if (samples.empty()) return;
    2507           0 :   base::TimeTicks start_time = samples[0].timestamp;
    2508             :   // The buffer needs space for 2 unsigned ints, 2 commas, \n and \0
    2509             :   const int kBufferSize = MaxDecimalDigitsIn<sizeof(
    2510             :                               base::TimeDelta().InMicroseconds())>::kUnsigned +
    2511             :                           MaxDecimalDigitsIn<sizeof(samples[0].id)>::kUnsigned +
    2512             :                           2 + 1 + 1;
    2513             :   EmbeddedVector<char, kBufferSize> buffer;
    2514             :   int i = 0;
    2515           0 :   for (const HeapObjectsMap::TimeInterval& sample : samples) {
    2516             :     int buffer_pos = 0;
    2517           0 :     if (i++ > 0) {
    2518           0 :       buffer[buffer_pos++] = ',';
    2519             :     }
    2520           0 :     base::TimeDelta time_delta = sample.timestamp - start_time;
    2521           0 :     buffer_pos = utoa(time_delta.InMicroseconds(), buffer, buffer_pos);
    2522           0 :     buffer[buffer_pos++] = ',';
    2523             :     buffer_pos = utoa(sample.last_assigned_id(), buffer, buffer_pos);
    2524           0 :     buffer[buffer_pos++] = '\n';
    2525           0 :     buffer[buffer_pos++] = '\0';
    2526           0 :     writer_->AddString(buffer.start());
    2527             :   }
    2528             : }
    2529             : 
    2530             : 
    2531      199187 : void HeapSnapshotJSONSerializer::SerializeString(const unsigned char* s) {
    2532      199187 :   writer_->AddCharacter('\n');
    2533      199187 :   writer_->AddCharacter('\"');
    2534     4180698 :   for ( ; *s != '\0'; ++s) {
    2535     3981511 :     switch (*s) {
    2536             :       case '\b':
    2537           5 :         writer_->AddString("\\b");
    2538           5 :         continue;
    2539             :       case '\f':
    2540           0 :         writer_->AddString("\\f");
    2541           0 :         continue;
    2542             :       case '\n':
    2543        1045 :         writer_->AddString("\\n");
    2544        1045 :         continue;
    2545             :       case '\r':
    2546           5 :         writer_->AddString("\\r");
    2547           5 :         continue;
    2548             :       case '\t':
    2549           0 :         writer_->AddString("\\t");
    2550           0 :         continue;
    2551             :       case '\"':
    2552             :       case '\\':
    2553         435 :         writer_->AddCharacter('\\');
    2554         435 :         writer_->AddCharacter(*s);
    2555         435 :         continue;
    2556             :       default:
    2557     3980021 :         if (*s > 31 && *s < 128) {
    2558     3980001 :           writer_->AddCharacter(*s);
    2559          20 :         } else if (*s <= 31) {
    2560             :           // Special character with no dedicated literal.
    2561           0 :           WriteUChar(writer_, *s);
    2562             :         } else {
    2563             :           // Convert UTF-8 into \u UTF-16 literal.
    2564          20 :           size_t length = 1, cursor = 0;
    2565          20 :           for ( ; length <= 4 && *(s + length) != '\0'; ++length) { }
    2566          20 :           unibrow::uchar c = unibrow::Utf8::CalculateValue(s, length, &cursor);
    2567          20 :           if (c != unibrow::Utf8::kBadChar) {
    2568          20 :             WriteUChar(writer_, c);
    2569             :             DCHECK_NE(cursor, 0);
    2570          20 :             s += cursor - 1;
    2571             :           } else {
    2572           0 :             writer_->AddCharacter('?');
    2573             :           }
    2574             :         }
    2575             :     }
    2576             :   }
    2577      199187 :   writer_->AddCharacter('\"');
    2578      199187 : }
    2579             : 
    2580             : 
    2581          30 : void HeapSnapshotJSONSerializer::SerializeStrings() {
    2582             :   ScopedVector<const unsigned char*> sorted_strings(
    2583          30 :       strings_.occupancy() + 1);
    2584      199247 :   for (base::HashMap::Entry* entry = strings_.Start(); entry != nullptr;
    2585             :        entry = strings_.Next(entry)) {
    2586      199187 :     int index = static_cast<int>(reinterpret_cast<uintptr_t>(entry->value));
    2587      398374 :     sorted_strings[index] = reinterpret_cast<const unsigned char*>(entry->key);
    2588             :   }
    2589      199217 :   writer_->AddString("\"<dummy>\"");
    2590      199217 :   for (int i = 1; i < sorted_strings.length(); ++i) {
    2591      199187 :     writer_->AddCharacter(',');
    2592      398374 :     SerializeString(sorted_strings[i]);
    2593      398404 :     if (writer_->aborted()) return;
    2594             :   }
    2595             : }
    2596             : 
    2597         365 : void HeapSnapshotJSONSerializer::SerializeLocation(
    2598             :     const SourceLocation& location) {
    2599             :   // The buffer needs space for 4 unsigned ints, 3 commas, \n and \0
    2600             :   static const int kBufferSize =
    2601             :       MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned * 4 + 3 + 2;
    2602             :   EmbeddedVector<char, kBufferSize> buffer;
    2603             :   int buffer_pos = 0;
    2604         365 :   buffer_pos = utoa(to_node_index(location.entry_index), buffer, buffer_pos);
    2605         730 :   buffer[buffer_pos++] = ',';
    2606         365 :   buffer_pos = utoa(location.scriptId, buffer, buffer_pos);
    2607         730 :   buffer[buffer_pos++] = ',';
    2608         365 :   buffer_pos = utoa(location.line, buffer, buffer_pos);
    2609         730 :   buffer[buffer_pos++] = ',';
    2610         365 :   buffer_pos = utoa(location.col, buffer, buffer_pos);
    2611         730 :   buffer[buffer_pos++] = '\n';
    2612         730 :   buffer[buffer_pos++] = '\0';
    2613         365 :   writer_->AddString(buffer.start());
    2614         365 : }
    2615             : 
    2616          30 : void HeapSnapshotJSONSerializer::SerializeLocations() {
    2617         790 :   const std::vector<SourceLocation>& locations = snapshot_->locations();
    2618         790 :   for (size_t i = 0; i < locations.size(); i++) {
    2619         730 :     if (i > 0) writer_->AddCharacter(',');
    2620         365 :     SerializeLocation(locations[i]);
    2621         760 :     if (writer_->aborted()) return;
    2622             :   }
    2623             : }
    2624             : 
    2625             : }  // namespace internal
    2626      178779 : }  // namespace v8

Generated by: LCOV version 1.10