LCOV - code coverage report
Current view: top level - src/profiler - heap-snapshot-generator.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1043 1213 86.0 %
Date: 2019-04-18 Functions: 118 159 74.2 %

          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/vector.h"
      37             : #include "src/visitors.h"
      38             : 
      39             : namespace v8 {
      40             : namespace internal {
      41             : 
      42           0 : HeapGraphEdge::HeapGraphEdge(Type type, const char* name, HeapEntry* from,
      43             :                              HeapEntry* to)
      44     9843767 :     : bit_field_(TypeField::encode(type) |
      45             :                  FromIndexField::encode(from->index())),
      46             :       to_entry_(to),
      47     9843767 :       name_(name) {
      48             :   DCHECK(type == kContextVariable
      49             :       || type == kProperty
      50             :       || type == kInternal
      51             :       || type == kShortcut
      52             :       || type == kWeak);
      53           0 : }
      54             : 
      55           0 : HeapGraphEdge::HeapGraphEdge(Type type, int index, HeapEntry* from,
      56             :                              HeapEntry* to)
      57     1140476 :     : bit_field_(TypeField::encode(type) |
      58             :                  FromIndexField::encode(from->index())),
      59             :       to_entry_(to),
      60     1140476 :       index_(index) {
      61             :   DCHECK(type == kElement || type == kHidden);
      62           0 : }
      63             : 
      64           0 : HeapEntry::HeapEntry(HeapSnapshot* snapshot, int index, Type type,
      65             :                      const char* name, SnapshotObjectId id, size_t self_size,
      66             :                      unsigned trace_node_id)
      67             :     : type_(type),
      68             :       index_(index),
      69             :       children_count_(0),
      70             :       self_size_(self_size),
      71             :       snapshot_(snapshot),
      72             :       name_(name),
      73             :       id_(id),
      74     3113073 :       trace_node_id_(trace_node_id) {
      75             :   DCHECK_GE(index, 0);
      76           0 : }
      77             : 
      78           0 : void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
      79             :                                   const char* name,
      80             :                                   HeapEntry* entry) {
      81     9843767 :   ++children_count_;
      82    19687534 :   snapshot_->edges().emplace_back(type, name, this, entry);
      83           0 : }
      84             : 
      85           0 : void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
      86             :                                     int index,
      87             :                                     HeapEntry* entry) {
      88     1140476 :   ++children_count_;
      89     2280952 :   snapshot_->edges().emplace_back(type, index, this, entry);
      90           0 : }
      91             : 
      92     1211383 : void HeapEntry::SetNamedAutoIndexReference(HeapGraphEdge::Type type,
      93             :                                            const char* description,
      94             :                                            HeapEntry* child,
      95             :                                            StringsStorage* names) {
      96     1211383 :   int index = children_count_ + 1;
      97             :   const char* name = description
      98             :                          ? names->GetFormatted("%d / %s", index, description)
      99     1211383 :                          : names->GetName(index);
     100             :   SetNamedReference(type, name, child);
     101     1211383 : }
     102             : 
     103           0 : void HeapEntry::Print(
     104             :     const char* prefix, const char* edge_name, int max_depth, int indent) {
     105             :   STATIC_ASSERT(sizeof(unsigned) == sizeof(id()));
     106             :   base::OS::Print("%6" PRIuS " @%6u %*c %s%s: ", self_size(), id(), indent, ' ',
     107           0 :                   prefix, edge_name);
     108           0 :   if (type() != kString) {
     109           0 :     base::OS::Print("%s %.40s\n", TypeAsString(), name_);
     110             :   } else {
     111           0 :     base::OS::Print("\"");
     112           0 :     const char* c = name_;
     113           0 :     while (*c && (c - name_) <= 40) {
     114           0 :       if (*c != '\n')
     115           0 :         base::OS::Print("%c", *c);
     116             :       else
     117           0 :         base::OS::Print("\\n");
     118           0 :       ++c;
     119             :     }
     120           0 :     base::OS::Print("\"\n");
     121             :   }
     122           0 :   if (--max_depth == 0) return;
     123           0 :   for (auto i = children_begin(); i != children_end(); ++i) {
     124           0 :     HeapGraphEdge& edge = **i;
     125             :     const char* edge_prefix = "";
     126             :     EmbeddedVector<char, 64> index;
     127             :     const char* edge_name = index.start();
     128           0 :     switch (edge.type()) {
     129             :       case HeapGraphEdge::kContextVariable:
     130             :         edge_prefix = "#";
     131             :         edge_name = edge.name();
     132           0 :         break;
     133             :       case HeapGraphEdge::kElement:
     134           0 :         SNPrintF(index, "%d", edge.index());
     135           0 :         break;
     136             :       case HeapGraphEdge::kInternal:
     137             :         edge_prefix = "$";
     138             :         edge_name = edge.name();
     139           0 :         break;
     140             :       case HeapGraphEdge::kProperty:
     141             :         edge_name = edge.name();
     142           0 :         break;
     143             :       case HeapGraphEdge::kHidden:
     144             :         edge_prefix = "$";
     145           0 :         SNPrintF(index, "%d", edge.index());
     146           0 :         break;
     147             :       case HeapGraphEdge::kShortcut:
     148             :         edge_prefix = "^";
     149             :         edge_name = edge.name();
     150           0 :         break;
     151             :       case HeapGraphEdge::kWeak:
     152             :         edge_prefix = "w";
     153             :         edge_name = edge.name();
     154           0 :         break;
     155             :       default:
     156           0 :         SNPrintF(index, "!!! unknown edge type: %d ", edge.type());
     157             :     }
     158           0 :     edge.to()->Print(edge_prefix, edge_name, max_depth, indent + 2);
     159             :   }
     160             : }
     161             : 
     162           0 : const char* HeapEntry::TypeAsString() {
     163           0 :   switch (type()) {
     164             :     case kHidden: return "/hidden/";
     165           0 :     case kObject: return "/object/";
     166           0 :     case kClosure: return "/closure/";
     167           0 :     case kString: return "/string/";
     168           0 :     case kCode: return "/code/";
     169           0 :     case kArray: return "/array/";
     170           0 :     case kRegExp: return "/regexp/";
     171           0 :     case kHeapNumber: return "/number/";
     172           0 :     case kNative: return "/native/";
     173           0 :     case kSynthetic: return "/synthetic/";
     174           0 :     case kConsString: return "/concatenated string/";
     175           0 :     case kSlicedString: return "/sliced string/";
     176           0 :     case kSymbol: return "/symbol/";
     177             :     case kBigInt:
     178           0 :       return "/bigint/";
     179           0 :     default: return "???";
     180             :   }
     181             : }
     182             : 
     183         796 : HeapSnapshot::HeapSnapshot(HeapProfiler* profiler) : profiler_(profiler) {
     184             :   // It is very important to keep objects that form a heap snapshot
     185             :   // as small as possible. Check assumptions about data structure sizes.
     186             :   STATIC_ASSERT((kSystemPointerSize == 4 && sizeof(HeapGraphEdge) == 12) ||
     187             :                 (kSystemPointerSize == 8 && sizeof(HeapGraphEdge) == 24));
     188             :   STATIC_ASSERT((kSystemPointerSize == 4 && sizeof(HeapEntry) == 28) ||
     189             :                 (kSystemPointerSize == 8 && sizeof(HeapEntry) == 40));
     190         398 :   memset(&gc_subroot_entries_, 0, sizeof(gc_subroot_entries_));
     191         398 : }
     192             : 
     193           5 : void HeapSnapshot::Delete() {
     194           5 :   profiler_->RemoveSnapshot(this);
     195           5 : }
     196             : 
     197           0 : void HeapSnapshot::RememberLastJSObjectId() {
     198         786 :   max_snapshot_js_object_id_ = profiler_->heap_object_map()->last_assigned_id();
     199           0 : }
     200             : 
     201         398 : void HeapSnapshot::AddSyntheticRootEntries() {
     202             :   AddRootEntry();
     203             :   AddGcRootsEntry();
     204             :   SnapshotObjectId id = HeapObjectsMap::kGcRootsFirstSubrootId;
     205       19502 :   for (int root = 0; root < static_cast<int>(Root::kNumberOfRoots); root++) {
     206        9552 :     AddGcSubrootEntry(static_cast<Root>(root), id);
     207        9552 :     id += HeapObjectsMap::kObjectIdStep;
     208             :   }
     209             :   DCHECK_EQ(HeapObjectsMap::kFirstAvailableObjectId, id);
     210         398 : }
     211             : 
     212           0 : void HeapSnapshot::AddRootEntry() {
     213             :   DCHECK_NULL(root_entry_);
     214             :   DCHECK(entries_.empty());  // Root entry must be the first one.
     215         398 :   root_entry_ = AddEntry(HeapEntry::kSynthetic, "",
     216         398 :                          HeapObjectsMap::kInternalRootObjectId, 0, 0);
     217             :   DCHECK_EQ(1u, entries_.size());
     218             :   DCHECK_EQ(root_entry_, &entries_.front());
     219           0 : }
     220             : 
     221           0 : void HeapSnapshot::AddGcRootsEntry() {
     222             :   DCHECK_NULL(gc_roots_entry_);
     223         398 :   gc_roots_entry_ = AddEntry(HeapEntry::kSynthetic, "(GC roots)",
     224         398 :                              HeapObjectsMap::kGcRootsObjectId, 0, 0);
     225           0 : }
     226             : 
     227        9552 : void HeapSnapshot::AddGcSubrootEntry(Root root, SnapshotObjectId id) {
     228             :   DCHECK_NULL(gc_subroot_entries_[static_cast<int>(root)]);
     229             :   gc_subroot_entries_[static_cast<int>(root)] =
     230        9552 :       AddEntry(HeapEntry::kSynthetic, RootVisitor::RootName(root), id, 0, 0);
     231        9552 : }
     232             : 
     233           0 : void HeapSnapshot::AddLocation(HeapEntry* entry, int scriptId, int line,
     234             :                                int col) {
     235      134691 :   locations_.emplace_back(entry->index(), scriptId, line, col);
     236           0 : }
     237             : 
     238     3113073 : HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
     239             :                                   const char* name,
     240             :                                   SnapshotObjectId id,
     241             :                                   size_t size,
     242             :                                   unsigned trace_node_id) {
     243             :   DCHECK(!is_complete());
     244     6226146 :   entries_.emplace_back(this, static_cast<int>(entries_.size()), type, name, id,
     245     3113073 :                         size, trace_node_id);
     246     3113073 :   return &entries_.back();
     247             : }
     248             : 
     249         393 : void HeapSnapshot::FillChildren() {
     250             :   DCHECK(children().empty());
     251             :   int children_index = 0;
     252     3097976 :   for (HeapEntry& entry : entries()) {
     253             :     children_index = entry.set_children_index(children_index);
     254             :   }
     255             :   DCHECK_EQ(edges().size(), static_cast<size_t>(children_index));
     256         393 :   children().resize(edges().size());
     257    10966366 :   for (HeapGraphEdge& edge : edges()) {
     258             :     edge.from()->add_child(&edge);
     259             :   }
     260         393 : }
     261             : 
     262      183299 : HeapEntry* HeapSnapshot::GetEntryById(SnapshotObjectId id) {
     263      183299 :   if (entries_by_id_cache_.empty()) {
     264          10 :     CHECK(is_complete());
     265             :     entries_by_id_cache_.reserve(entries_.size());
     266       67493 :     for (HeapEntry& entry : entries_) {
     267      134966 :       entries_by_id_cache_.emplace(entry.id(), &entry);
     268             :     }
     269             :   }
     270             :   auto it = entries_by_id_cache_.find(id);
     271      183299 :   return it != entries_by_id_cache_.end() ? it->second : nullptr;
     272             : }
     273             : 
     274           0 : void HeapSnapshot::Print(int max_depth) {
     275           0 :   root()->Print("", "", max_depth, 0);
     276           0 : }
     277             : 
     278             : // We split IDs on evens for embedder objects (see
     279             : // HeapObjectsMap::GenerateId) and odds for native objects.
     280             : const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = 1;
     281             : const SnapshotObjectId HeapObjectsMap::kGcRootsObjectId =
     282             :     HeapObjectsMap::kInternalRootObjectId + HeapObjectsMap::kObjectIdStep;
     283             : const SnapshotObjectId HeapObjectsMap::kGcRootsFirstSubrootId =
     284             :     HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep;
     285             : const SnapshotObjectId HeapObjectsMap::kFirstAvailableObjectId =
     286             :     HeapObjectsMap::kGcRootsFirstSubrootId +
     287             :     static_cast<int>(Root::kNumberOfRoots) * HeapObjectsMap::kObjectIdStep;
     288             : 
     289       66326 : HeapObjectsMap::HeapObjectsMap(Heap* heap)
     290      132652 :     : next_id_(kFirstAvailableObjectId), heap_(heap) {
     291             :   // The dummy element at zero index is needed as entries_map_ cannot hold
     292             :   // an entry with zero value. Otherwise it's impossible to tell if
     293             :   // LookupOrInsert has added a new item or just returning exisiting one
     294             :   // having the value of zero.
     295       66326 :   entries_.emplace_back(0, kNullAddress, 0, true);
     296       66326 : }
     297             : 
     298      128397 : bool HeapObjectsMap::MoveObject(Address from, Address to, int object_size) {
     299             :   DCHECK_NE(kNullAddress, to);
     300             :   DCHECK_NE(kNullAddress, from);
     301      128397 :   if (from == to) return false;
     302      256794 :   void* from_value = entries_map_.Remove(reinterpret_cast<void*>(from),
     303      128397 :                                          ComputeAddressHash(from));
     304      128397 :   if (from_value == nullptr) {
     305             :     // It may occur that some untracked object moves to an address X and there
     306             :     // is a tracked object at that address. In this case we should remove the
     307             :     // entry as we know that the object has died.
     308      253264 :     void* to_value = entries_map_.Remove(reinterpret_cast<void*>(to),
     309      126632 :                                          ComputeAddressHash(to));
     310      126632 :     if (to_value != nullptr) {
     311             :       int to_entry_info_index =
     312        2254 :           static_cast<int>(reinterpret_cast<intptr_t>(to_value));
     313        4508 :       entries_.at(to_entry_info_index).addr = kNullAddress;
     314             :     }
     315             :   } else {
     316        3530 :     base::HashMap::Entry* to_entry = entries_map_.LookupOrInsert(
     317             :         reinterpret_cast<void*>(to), ComputeAddressHash(to));
     318        1765 :     if (to_entry->value != nullptr) {
     319             :       // We found the existing entry with to address for an old object.
     320             :       // Without this operation we will have two EntryInfo's with the same
     321             :       // value in addr field. It is bad because later at RemoveDeadEntries
     322             :       // one of this entry will be removed with the corresponding entries_map_
     323             :       // entry.
     324             :       int to_entry_info_index =
     325           0 :           static_cast<int>(reinterpret_cast<intptr_t>(to_entry->value));
     326           0 :       entries_.at(to_entry_info_index).addr = kNullAddress;
     327             :     }
     328             :     int from_entry_info_index =
     329        1765 :         static_cast<int>(reinterpret_cast<intptr_t>(from_value));
     330        3530 :     entries_.at(from_entry_info_index).addr = to;
     331             :     // Size of an object can change during its life, so to keep information
     332             :     // about the object in entries_ consistent, we have to adjust size when the
     333             :     // object is migrated.
     334        1765 :     if (FLAG_heap_profiler_trace_objects) {
     335           0 :       PrintF("Move object from %p to %p old size %6d new size %6d\n",
     336             :              reinterpret_cast<void*>(from), reinterpret_cast<void*>(to),
     337           0 :              entries_.at(from_entry_info_index).size, object_size);
     338             :     }
     339        1765 :     entries_.at(from_entry_info_index).size = object_size;
     340        1765 :     to_entry->value = from_value;
     341             :   }
     342      128397 :   return from_value != nullptr;
     343             : }
     344             : 
     345             : 
     346           0 : void HeapObjectsMap::UpdateObjectSize(Address addr, int size) {
     347           0 :   FindOrAddEntry(addr, size, false);
     348           0 : }
     349             : 
     350             : 
     351      919883 : SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) {
     352      919883 :   base::HashMap::Entry* entry = entries_map_.Lookup(
     353             :       reinterpret_cast<void*>(addr), ComputeAddressHash(addr));
     354      919883 :   if (entry == nullptr) return 0;
     355      591801 :   int entry_index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
     356      591801 :   EntryInfo& entry_info = entries_.at(entry_index);
     357             :   DCHECK(static_cast<uint32_t>(entries_.size()) > entries_map_.occupancy());
     358      591801 :   return entry_info.id;
     359             : }
     360             : 
     361             : 
     362     3893283 : SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr,
     363             :                                                 unsigned int size,
     364             :                                                 bool accessed) {
     365             :   DCHECK(static_cast<uint32_t>(entries_.size()) > entries_map_.occupancy());
     366     7786566 :   base::HashMap::Entry* entry = entries_map_.LookupOrInsert(
     367             :       reinterpret_cast<void*>(addr), ComputeAddressHash(addr));
     368     3893283 :   if (entry->value != nullptr) {
     369             :     int entry_index =
     370      976523 :         static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
     371      976523 :     EntryInfo& entry_info = entries_.at(entry_index);
     372      976523 :     entry_info.accessed = accessed;
     373      976523 :     if (FLAG_heap_profiler_trace_objects) {
     374           0 :       PrintF("Update object size : %p with old size %d and new size %d\n",
     375           0 :              reinterpret_cast<void*>(addr), entry_info.size, size);
     376             :     }
     377      976523 :     entry_info.size = size;
     378      976523 :     return entry_info.id;
     379             :   }
     380     2916760 :   entry->value = reinterpret_cast<void*>(entries_.size());
     381     2916760 :   SnapshotObjectId id = next_id_;
     382     2916760 :   next_id_ += kObjectIdStep;
     383     5833520 :   entries_.push_back(EntryInfo(id, addr, size, accessed));
     384             :   DCHECK(static_cast<uint32_t>(entries_.size()) > entries_map_.occupancy());
     385     2916760 :   return id;
     386             : }
     387             : 
     388        7848 : void HeapObjectsMap::StopHeapObjectsTracking() { time_intervals_.clear(); }
     389             : 
     390         100 : void HeapObjectsMap::UpdateHeapObjectsMap() {
     391         100 :   if (FLAG_heap_profiler_trace_objects) {
     392             :     PrintF("Begin HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n",
     393           0 :            entries_map_.occupancy());
     394             :   }
     395         100 :   heap_->PreciseCollectAllGarbage(Heap::kNoGCFlags,
     396         100 :                                   GarbageCollectionReason::kHeapProfiler);
     397         200 :   HeapIterator iterator(heap_);
     398     1344050 :   for (HeapObject obj = iterator.next(); !obj.is_null();
     399             :        obj = iterator.next()) {
     400     1343850 :     FindOrAddEntry(obj->address(), obj->Size());
     401      671925 :     if (FLAG_heap_profiler_trace_objects) {
     402           0 :       PrintF("Update object      : %p %6d. Next address is %p\n",
     403             :              reinterpret_cast<void*>(obj->address()), obj->Size(),
     404           0 :              reinterpret_cast<void*>(obj->address() + obj->Size()));
     405             :     }
     406             :   }
     407         100 :   RemoveDeadEntries();
     408         100 :   if (FLAG_heap_profiler_trace_objects) {
     409             :     PrintF("End HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n",
     410           0 :            entries_map_.occupancy());
     411             :   }
     412         100 : }
     413             : 
     414          55 : SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream,
     415             :                                                       int64_t* timestamp_us) {
     416          55 :   UpdateHeapObjectsMap();
     417          55 :   time_intervals_.emplace_back(next_id_);
     418          55 :   int prefered_chunk_size = stream->GetChunkSize();
     419             :   std::vector<v8::HeapStatsUpdate> stats_buffer;
     420             :   DCHECK(!entries_.empty());
     421             :   EntryInfo* entry_info = &entries_.front();
     422             :   EntryInfo* end_entry_info = &entries_.back() + 1;
     423         615 :   for (size_t time_interval_index = 0;
     424             :        time_interval_index < time_intervals_.size(); ++time_interval_index) {
     425             :     TimeInterval& time_interval = time_intervals_[time_interval_index];
     426         280 :     SnapshotObjectId time_interval_id = time_interval.id;
     427             :     uint32_t entries_size = 0;
     428             :     EntryInfo* start_entry_info = entry_info;
     429      738566 :     while (entry_info < end_entry_info && entry_info->id < time_interval_id) {
     430      369143 :       entries_size += entry_info->size;
     431      369143 :       ++entry_info;
     432             :     }
     433             :     uint32_t entries_count =
     434         280 :         static_cast<uint32_t>(entry_info - start_entry_info);
     435         510 :     if (time_interval.count != entries_count ||
     436         230 :         time_interval.size != entries_size) {
     437         100 :       stats_buffer.emplace_back(static_cast<uint32_t>(time_interval_index),
     438             :                                 time_interval.count = entries_count,
     439          50 :                                 time_interval.size = entries_size);
     440          50 :       if (static_cast<int>(stats_buffer.size()) >= prefered_chunk_size) {
     441             :         OutputStream::WriteResult result = stream->WriteHeapStatsChunk(
     442           0 :             &stats_buffer.front(), static_cast<int>(stats_buffer.size()));
     443           0 :         if (result == OutputStream::kAbort) return last_assigned_id();
     444             :         stats_buffer.clear();
     445             :       }
     446             :     }
     447             :   }
     448             :   DCHECK(entry_info == end_entry_info);
     449          55 :   if (!stats_buffer.empty()) {
     450          45 :     OutputStream::WriteResult result = stream->WriteHeapStatsChunk(
     451          90 :         &stats_buffer.front(), static_cast<int>(stats_buffer.size()));
     452          45 :     if (result == OutputStream::kAbort) return last_assigned_id();
     453             :   }
     454          55 :   stream->EndOfStream();
     455          55 :   if (timestamp_us) {
     456             :     *timestamp_us =
     457         110 :         (time_intervals_.back().timestamp - time_intervals_.front().timestamp)
     458          55 :             .InMicroseconds();
     459             :   }
     460          55 :   return last_assigned_id();
     461             : }
     462             : 
     463             : 
     464         498 : void HeapObjectsMap::RemoveDeadEntries() {
     465             :   DCHECK(entries_.size() > 0 && entries_.at(0).id == 0 &&
     466             :          entries_.at(0).addr == kNullAddress);
     467             :   size_t first_free_entry = 1;
     468     7649876 :   for (size_t i = 1; i < entries_.size(); ++i) {
     469             :     EntryInfo& entry_info = entries_.at(i);
     470     3824689 :     if (entry_info.accessed) {
     471     3774570 :       if (first_free_entry != i) {
     472       91156 :         entries_.at(first_free_entry) = entry_info;
     473             :       }
     474     3774570 :       entries_.at(first_free_entry).accessed = false;
     475             :       base::HashMap::Entry* entry =
     476     7549140 :           entries_map_.Lookup(reinterpret_cast<void*>(entry_info.addr),
     477             :                               ComputeAddressHash(entry_info.addr));
     478             :       DCHECK(entry);
     479     3774570 :       entry->value = reinterpret_cast<void*>(first_free_entry);
     480     3774570 :       ++first_free_entry;
     481             :     } else {
     482       50119 :       if (entry_info.addr) {
     483       95730 :         entries_map_.Remove(reinterpret_cast<void*>(entry_info.addr),
     484       47865 :                             ComputeAddressHash(entry_info.addr));
     485             :       }
     486             :     }
     487             :   }
     488         498 :   entries_.erase(entries_.begin() + first_free_entry, entries_.end());
     489             : 
     490             :   DCHECK(static_cast<uint32_t>(entries_.size()) - 1 ==
     491             :          entries_map_.occupancy());
     492         498 : }
     493             : 
     494         398 : V8HeapExplorer::V8HeapExplorer(HeapSnapshot* snapshot,
     495             :                                SnapshottingProgressReportingInterface* progress,
     496             :                                v8::HeapProfiler::ObjectNameResolver* resolver)
     497             :     : heap_(snapshot->profiler()->heap_object_map()->heap()),
     498             :       snapshot_(snapshot),
     499             :       names_(snapshot_->profiler()->names()),
     500             :       heap_object_map_(snapshot_->profiler()->heap_object_map()),
     501             :       progress_(progress),
     502             :       generator_(nullptr),
     503        2388 :       global_object_name_resolver_(resolver) {}
     504             : 
     505     3102635 : HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) {
     506     3102635 :   return AddEntry(HeapObject::cast(Object(reinterpret_cast<Address>(ptr))));
     507             : }
     508             : 
     509     3026852 : void V8HeapExplorer::ExtractLocation(HeapEntry* entry, HeapObject object) {
     510     3026852 :   if (object->IsJSFunction()) {
     511      282524 :     JSFunction func = JSFunction::cast(object);
     512      282524 :     ExtractLocationForJSFunction(entry, func);
     513             : 
     514     2744328 :   } else if (object->IsJSGeneratorObject()) {
     515             :     JSGeneratorObject gen = JSGeneratorObject::cast(object);
     516          10 :     ExtractLocationForJSFunction(entry, gen->function());
     517             : 
     518     2744318 :   } else if (object->IsJSObject()) {
     519      141817 :     JSObject obj = JSObject::cast(object);
     520      141817 :     JSFunction maybe_constructor = GetConstructor(obj);
     521             : 
     522      141817 :     if (!maybe_constructor.is_null()) {
     523      109318 :       ExtractLocationForJSFunction(entry, maybe_constructor);
     524             :     }
     525             :   }
     526     3026852 : }
     527             : 
     528      391852 : void V8HeapExplorer::ExtractLocationForJSFunction(HeapEntry* entry,
     529             :                                                   JSFunction func) {
     530     1040865 :   if (!func->shared()->script()->IsScript()) return;
     531      134691 :   Script script = Script::cast(func->shared()->script());
     532             :   int scriptId = script->id();
     533      134691 :   int start = func->shared()->StartPosition();
     534      134691 :   int line = script->GetLineNumber(start);
     535      134691 :   int col = script->GetColumnNumber(start);
     536      134691 :   snapshot_->AddLocation(entry, scriptId, line, col);
     537             : }
     538             : 
     539     3102635 : HeapEntry* V8HeapExplorer::AddEntry(HeapObject object) {
     540     3102635 :   if (object->IsJSFunction()) {
     541             :     JSFunction func = JSFunction::cast(object);
     542      282524 :     SharedFunctionInfo shared = func->shared();
     543      282524 :     const char* name = names_->GetName(shared->Name());
     544      282524 :     return AddEntry(object, HeapEntry::kClosure, name);
     545     2820111 :   } else if (object->IsJSBoundFunction()) {
     546         398 :     return AddEntry(object, HeapEntry::kClosure, "native_bind");
     547     2819713 :   } else if (object->IsJSRegExp()) {
     548             :     JSRegExp re = JSRegExp::cast(object);
     549           0 :     return AddEntry(object,
     550             :                     HeapEntry::kRegExp,
     551           0 :                     names_->GetName(re->Pattern()));
     552     2819713 :   } else if (object->IsJSObject()) {
     553      141434 :     const char* name = names_->GetName(
     554      282868 :         GetConstructorName(JSObject::cast(object)));
     555      141434 :     if (object->IsJSGlobalObject()) {
     556         796 :       auto it = objects_tags_.find(JSGlobalObject::cast(object));
     557         398 :       if (it != objects_tags_.end()) {
     558          30 :         name = names_->GetFormatted("%s / %s", name, it->second);
     559             :       }
     560             :     }
     561      141434 :     return AddEntry(object, HeapEntry::kObject, name);
     562     2678279 :   } else if (object->IsString()) {
     563             :     String string = String::cast(object);
     564      606389 :     if (string->IsConsString()) {
     565      120020 :       return AddEntry(object, HeapEntry::kConsString, "(concatenated string)");
     566      486369 :     } else if (string->IsSlicedString()) {
     567           5 :       return AddEntry(object, HeapEntry::kSlicedString, "(sliced string)");
     568             :     } else {
     569      486364 :       return AddEntry(object, HeapEntry::kString,
     570      972728 :                       names_->GetName(String::cast(object)));
     571             :     }
     572     2071890 :   } else if (object->IsSymbol()) {
     573       17149 :     if (Symbol::cast(object)->is_private())
     574       11572 :       return AddEntry(object, HeapEntry::kHidden, "private symbol");
     575             :     else
     576        5577 :       return AddEntry(object, HeapEntry::kSymbol, "symbol");
     577     2054741 :   } else if (object->IsBigInt()) {
     578          10 :     return AddEntry(object, HeapEntry::kBigInt, "bigint");
     579     2054731 :   } else if (object->IsCode()) {
     580      607224 :     return AddEntry(object, HeapEntry::kCode, "");
     581     1447507 :   } else if (object->IsSharedFunctionInfo()) {
     582      293449 :     String name = SharedFunctionInfo::cast(object)->Name();
     583      293449 :     return AddEntry(object, HeapEntry::kCode, names_->GetName(name));
     584     1154058 :   } else if (object->IsScript()) {
     585             :     Object name = Script::cast(object)->name();
     586        1935 :     return AddEntry(
     587             :         object, HeapEntry::kCode,
     588        1935 :         name->IsString() ? names_->GetName(String::cast(name)) : "");
     589     1152566 :   } else if (object->IsNativeContext()) {
     590         398 :     return AddEntry(object, HeapEntry::kHidden, "system / NativeContext");
     591     1152168 :   } else if (object->IsContext()) {
     592        2040 :     return AddEntry(object, HeapEntry::kObject, "system / Context");
     593     3425443 :   } else if (object->IsFixedArray() || object->IsFixedDoubleArray() ||
     594             :              object->IsByteArray()) {
     595       16781 :     return AddEntry(object, HeapEntry::kArray, "");
     596     1133347 :   } else if (object->IsHeapNumber()) {
     597       14187 :     return AddEntry(object, HeapEntry::kHeapNumber, "number");
     598             :   }
     599     1119160 :   return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object));
     600             : }
     601             : 
     602     3102635 : HeapEntry* V8HeapExplorer::AddEntry(HeapObject object, HeapEntry::Type type,
     603             :                                     const char* name) {
     604     6205270 :   return AddEntry(object->address(), type, name, object->Size());
     605             : }
     606             : 
     607     3102645 : HeapEntry* V8HeapExplorer::AddEntry(Address address,
     608             :                                     HeapEntry::Type type,
     609             :                                     const char* name,
     610             :                                     size_t size) {
     611     3102645 :   SnapshotObjectId object_id = heap_object_map_->FindOrAddEntry(
     612     3102645 :       address, static_cast<unsigned int>(size));
     613             :   unsigned trace_node_id = 0;
     614     3102645 :   if (AllocationTracker* allocation_tracker =
     615     3102645 :       snapshot_->profiler()->allocation_tracker()) {
     616             :     trace_node_id =
     617       33543 :         allocation_tracker->address_to_trace()->GetTraceNodeId(address);
     618             :   }
     619     3102645 :   return snapshot_->AddEntry(type, name, object_id, size, trace_node_id);
     620             : }
     621             : 
     622     1119160 : const char* V8HeapExplorer::GetSystemEntryName(HeapObject object) {
     623     1119160 :   switch (object->map()->instance_type()) {
     624             :     case MAP_TYPE:
     625      177445 :       switch (Map::cast(object)->instance_type()) {
     626             : #define MAKE_STRING_MAP_CASE(instance_type, size, name, Name) \
     627             :         case instance_type: return "system / Map (" #Name ")";
     628         398 :       STRING_TYPE_LIST(MAKE_STRING_MAP_CASE)
     629             : #undef MAKE_STRING_MAP_CASE
     630      169883 :         default: return "system / Map";
     631             :       }
     632             :     case CELL_TYPE: return "system / Cell";
     633       28896 :     case PROPERTY_CELL_TYPE: return "system / PropertyCell";
     634       27351 :     case FOREIGN_TYPE: return "system / Foreign";
     635        4776 :     case ODDBALL_TYPE: return "system / Oddball";
     636             :     case ALLOCATION_SITE_TYPE:
     637          16 :       return "system / AllocationSite";
     638             : #define MAKE_STRUCT_CASE(TYPE, Name, name) \
     639             :   case TYPE:                               \
     640             :     return "system / " #Name;
     641          10 :       STRUCT_LIST(MAKE_STRUCT_CASE)
     642             : #undef MAKE_STRUCT_CASE
     643      809780 :     default: return "system";
     644             :   }
     645             : }
     646             : 
     647          15 : int V8HeapExplorer::EstimateObjectsCount() {
     648          30 :   HeapIterator it(heap_, HeapIterator::kFilterUnreachable);
     649             :   int objects_count = 0;
     650      196494 :   while (!it.next().is_null()) ++objects_count;
     651          15 :   return objects_count;
     652             : }
     653             : 
     654     6053704 : class IndexedReferencesExtractor : public ObjectVisitor {
     655             :  public:
     656             :   IndexedReferencesExtractor(V8HeapExplorer* generator, HeapObject parent_obj,
     657             :                              HeapEntry* parent)
     658             :       : generator_(generator),
     659             :         parent_obj_(parent_obj),
     660             :         parent_start_(parent_obj_.RawMaybeWeakField(0)),
     661     3026852 :         parent_end_(parent_obj_.RawMaybeWeakField(parent_obj_->Size())),
     662             :         parent_(parent),
     663     9080556 :         next_index_(0) {}
     664     6484337 :   void VisitPointers(HeapObject host, ObjectSlot start,
     665             :                      ObjectSlot end) override {
     666    12968674 :     VisitPointers(host, MaybeObjectSlot(start), MaybeObjectSlot(end));
     667     6484337 :   }
     668     6734104 :   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     6734104 :     CHECK_LE(parent_start_, start);
     673     6734104 :     CHECK_LE(end, parent_end_);
     674    29633656 :     for (MaybeObjectSlot p = start; p < end; ++p) {
     675    16165448 :       int field_index = static_cast<int>(p - parent_start_);
     676    32330896 :       if (generator_->visited_fields_[field_index]) {
     677             :         generator_->visited_fields_[field_index] = false;
     678             :         continue;
     679             :       }
     680             :       HeapObject heap_object;
     681     3636677 :       if ((*p)->GetHeapObject(&heap_object)) {
     682             :         VisitHeapObjectImpl(heap_object, field_index);
     683             :       }
     684             :     }
     685     6734104 :   }
     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        1029 :   void VisitEmbeddedPointer(Code host, RelocInfo* rinfo) override {
     693             :     VisitHeapObjectImpl(rinfo->target_object(), -1);
     694        1029 :   }
     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     1903452 :     generator_->SetHiddenReference(parent_obj_, parent_, next_index_++,
     703     1903452 :                                    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     3026852 : void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject obj) {
     715     3026852 :   if (obj->IsJSGlobalProxy()) {
     716             :     ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
     717     3026459 :   } else if (obj->IsJSArrayBuffer()) {
     718          15 :     ExtractJSArrayBufferReferences(entry, JSArrayBuffer::cast(obj));
     719     3026444 :   } else if (obj->IsJSObject()) {
     720      423943 :     if (obj->IsJSWeakSet()) {
     721             :       ExtractJSWeakCollectionReferences(entry, JSWeakSet::cast(obj));
     722      423938 :     } else if (obj->IsJSWeakMap()) {
     723             :       ExtractJSWeakCollectionReferences(entry, JSWeakMap::cast(obj));
     724      423928 :     } else if (obj->IsJSSet()) {
     725             :       ExtractJSCollectionReferences(entry, JSSet::cast(obj));
     726      423923 :     } else if (obj->IsJSMap()) {
     727             :       ExtractJSCollectionReferences(entry, JSMap::cast(obj));
     728      423918 :     } else if (obj->IsJSPromise()) {
     729             :       ExtractJSPromiseReferences(entry, JSPromise::cast(obj));
     730      423893 :     } else if (obj->IsJSGeneratorObject()) {
     731          10 :       ExtractJSGeneratorObjectReferences(entry, JSGeneratorObject::cast(obj));
     732             :     }
     733      423943 :     ExtractJSObjectReferences(entry, JSObject::cast(obj));
     734     2602501 :   } else if (obj->IsString()) {
     735      603199 :     ExtractStringReferences(entry, String::cast(obj));
     736     1999302 :   } else if (obj->IsSymbol()) {
     737             :     ExtractSymbolReferences(entry, Symbol::cast(obj));
     738     1992700 :   } else if (obj->IsMap()) {
     739      137697 :     ExtractMapReferences(entry, Map::cast(obj));
     740     1855003 :   } else if (obj->IsSharedFunctionInfo()) {
     741      290344 :     ExtractSharedFunctionInfoReferences(entry, SharedFunctionInfo::cast(obj));
     742     1564659 :   } else if (obj->IsScript()) {
     743        1487 :     ExtractScriptReferences(entry, Script::cast(obj));
     744     1563172 :   } else if (obj->IsAccessorInfo()) {
     745        4323 :     ExtractAccessorInfoReferences(entry, AccessorInfo::cast(obj));
     746     1558849 :   } else if (obj->IsAccessorPair()) {
     747       28431 :     ExtractAccessorPairReferences(entry, AccessorPair::cast(obj));
     748     1530418 :   } else if (obj->IsCode()) {
     749      599609 :     ExtractCodeReferences(entry, Code::cast(obj));
     750      930809 :   } else if (obj->IsCell()) {
     751             :     ExtractCellReferences(entry, Cell::cast(obj));
     752      928132 :   } else if (obj->IsFeedbackCell()) {
     753       34485 :     ExtractFeedbackCellReferences(entry, FeedbackCell::cast(obj));
     754      893647 :   } else if (obj->IsPropertyCell()) {
     755       28438 :     ExtractPropertyCellReferences(entry, PropertyCell::cast(obj));
     756      865209 :   } else if (obj->IsAllocationSite()) {
     757          16 :     ExtractAllocationSiteReferences(entry, AllocationSite::cast(obj));
     758      865193 :   } else if (obj->IsArrayBoilerplateDescription()) {
     759             :     ExtractArrayBoilerplateDescriptionReferences(
     760             :         entry, ArrayBoilerplateDescription::cast(obj));
     761      865168 :   } else if (obj->IsFeedbackVector()) {
     762         448 :     ExtractFeedbackVectorReferences(entry, FeedbackVector::cast(obj));
     763      864720 :   } else if (obj->IsDescriptorArray()) {
     764       80777 :     ExtractDescriptorArrayReferences(entry, DescriptorArray::cast(obj));
     765      783943 :   } else if (obj->IsWeakFixedArray()) {
     766             :     ExtractWeakArrayReferences(WeakFixedArray::kHeaderSize, entry,
     767        5099 :                                WeakFixedArray::cast(obj));
     768      778844 :   } else if (obj->IsWeakArrayList()) {
     769             :     ExtractWeakArrayReferences(WeakArrayList::kHeaderSize, entry,
     770        1514 :                                WeakArrayList::cast(obj));
     771      777330 :   } else if (obj->IsContext()) {
     772        2433 :     ExtractContextReferences(entry, Context::cast(obj));
     773      774897 :   } else if (obj->IsEphemeronHashTable()) {
     774          15 :     ExtractEphemeronHashTableReferences(entry, EphemeronHashTable::cast(obj));
     775      774882 :   } else if (obj->IsFixedArray()) {
     776       10408 :     ExtractFixedArrayReferences(entry, FixedArray::cast(obj));
     777             :   }
     778     3026852 : }
     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      423943 : void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry,
     787             :                                                JSObject js_obj) {
     788             :   HeapObject obj = js_obj;
     789      423943 :   ExtractPropertyReferences(js_obj, entry);
     790      423943 :   ExtractElementReferences(js_obj, entry);
     791      423943 :   ExtractInternalReferences(js_obj, entry);
     792      423943 :   Isolate* isolate = Isolate::FromHeap(heap_);
     793             :   PrototypeIterator iter(isolate, js_obj);
     794             :   ReadOnlyRoots roots(isolate);
     795      847886 :   SetPropertyReference(entry, roots.proto_string(), iter.GetCurrent());
     796      423943 :   if (obj->IsJSBoundFunction()) {
     797             :     JSBoundFunction js_fun = JSBoundFunction::cast(obj);
     798         398 :     TagObject(js_fun->bound_arguments(), "(bound arguments)");
     799         796 :     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         796 :                          js_fun->bound_target_function(),
     805         398 :                          JSBoundFunction::kBoundTargetFunctionOffset);
     806             :     FixedArray bindings = js_fun->bound_arguments();
     807         418 :     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      423545 :   } else if (obj->IsJSFunction()) {
     812      282524 :     JSFunction js_fun = JSFunction::cast(js_obj);
     813      282524 :     if (js_fun->has_prototype_slot()) {
     814             :       Object proto_or_map = js_fun->prototype_or_initial_map();
     815       68682 :       if (!proto_or_map->IsTheHole(isolate)) {
     816       34774 :         if (!proto_or_map->IsMap()) {
     817          10 :           SetPropertyReference(entry, roots.prototype_string(), proto_or_map,
     818             :                                nullptr,
     819           5 :                                JSFunction::kPrototypeOrInitialMapOffset);
     820             :         } else {
     821      104307 :           SetPropertyReference(entry, roots.prototype_string(),
     822       34769 :                                js_fun->prototype());
     823             :           SetInternalReference(entry, "initial_map", proto_or_map,
     824       34769 :                                JSFunction::kPrototypeOrInitialMapOffset);
     825             :         }
     826             :       }
     827             :     }
     828      282524 :     SharedFunctionInfo shared_info = js_fun->shared();
     829      282524 :     TagObject(js_fun->raw_feedback_cell(), "(function feedback cell)");
     830      565048 :     SetInternalReference(entry, "feedback_cell", js_fun->raw_feedback_cell(),
     831      282524 :                          JSFunction::kFeedbackCellOffset);
     832      282524 :     TagObject(shared_info, "(shared function info)");
     833             :     SetInternalReference(entry, "shared", shared_info,
     834      282524 :                          JSFunction::kSharedFunctionInfoOffset);
     835      282524 :     TagObject(js_fun->context(), "(context)");
     836      565048 :     SetInternalReference(entry, "context", js_fun->context(),
     837      282524 :                          JSFunction::kContextOffset);
     838      565048 :     SetInternalReference(entry, "code", js_fun->code(),
     839      282524 :                          JSFunction::kCodeOffset);
     840      141021 :   } else if (obj->IsJSGlobalObject()) {
     841             :     JSGlobalObject global_obj = JSGlobalObject::cast(obj);
     842         786 :     SetInternalReference(entry, "native_context", global_obj->native_context(),
     843         393 :                          JSGlobalObject::kNativeContextOffset);
     844         786 :     SetInternalReference(entry, "global_proxy", global_obj->global_proxy(),
     845         393 :                          JSGlobalObject::kGlobalProxyOffset);
     846             :     STATIC_ASSERT(JSGlobalObject::kSize - JSObject::kHeaderSize ==
     847             :                   2 * kTaggedSize);
     848      140628 :   } else if (obj->IsJSArrayBufferView()) {
     849             :     JSArrayBufferView view = JSArrayBufferView::cast(obj);
     850             :     SetInternalReference(entry, "buffer", view->buffer(),
     851           5 :                          JSArrayBufferView::kBufferOffset);
     852             :   }
     853             : 
     854      423943 :   TagObject(js_obj->raw_properties_or_hash(), "(object properties)");
     855             :   SetInternalReference(entry, "properties", js_obj->raw_properties_or_hash(),
     856      423943 :                        JSObject::kPropertiesOrHashOffset);
     857             : 
     858      423943 :   TagObject(js_obj->elements(), "(object elements)");
     859      847886 :   SetInternalReference(entry, "elements", js_obj->elements(),
     860      423943 :                        JSObject::kElementsOffset);
     861      423943 : }
     862             : 
     863      603199 : void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, String string) {
     864      603199 :   if (string->IsConsString()) {
     865             :     ConsString cs = ConsString::cast(string);
     866      120020 :     SetInternalReference(entry, "first", cs->first(), ConsString::kFirstOffset);
     867      240040 :     SetInternalReference(entry, "second", cs->second(),
     868      120020 :                          ConsString::kSecondOffset);
     869      483179 :   } else if (string->IsSlicedString()) {
     870             :     SlicedString ss = SlicedString::cast(string);
     871          10 :     SetInternalReference(entry, "parent", ss->parent(),
     872           5 :                          SlicedString::kParentOffset);
     873      483174 :   } else if (string->IsThinString()) {
     874             :     ThinString ts = ThinString::cast(string);
     875           0 :     SetInternalReference(entry, "actual", ts->actual(),
     876           0 :                          ThinString::kActualOffset);
     877             :   }
     878      603199 : }
     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         135 :   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             :     Object key = table->get(key_index);
     903             :     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             :     HeapEntry* key_entry = GetEntry(key);
     909             :     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          60 :       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       69184 :     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         438 :       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      189819 :     for (size_t i = 0; i < arraysize(native_context_names); i++) {
     969       94713 :       int index = native_context_names[i].index;
     970       94713 :       const char* name = native_context_names[i].name;
     971             :       SetInternalReference(entry, name, context->get(index),
     972       94713 :                            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      137697 : void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map map) {
     992             :   MaybeObject maybe_raw_transitions_or_prototype_info = map->raw_transitions();
     993             :   HeapObject raw_transitions_or_prototype_info;
     994      137697 :   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      137508 :   } else if (maybe_raw_transitions_or_prototype_info->GetHeapObjectIfStrong(
    1000             :                  &raw_transitions_or_prototype_info)) {
    1001       26296 :     if (raw_transitions_or_prototype_info->IsTransitionArray()) {
    1002             :       TransitionArray transitions =
    1003             :           TransitionArray::cast(raw_transitions_or_prototype_info);
    1004        5512 :       if (map->CanTransition() && transitions->HasPrototypeTransitions()) {
    1005         786 :         TagObject(transitions->GetPrototypeTransitions(),
    1006         393 :                   "(prototype transitions)");
    1007             :       }
    1008        2756 :       TagObject(transitions, "(transition array)");
    1009             :       SetInternalReference(entry, "transitions", transitions,
    1010        2756 :                            Map::kTransitionsOrPrototypeInfoOffset);
    1011       47080 :     } 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       23540 :     } else if (map->is_prototype_map()) {
    1018       23540 :       TagObject(raw_transitions_or_prototype_info, "prototype_info");
    1019             :       SetInternalReference(entry, "prototype_info",
    1020             :                            raw_transitions_or_prototype_info,
    1021       23540 :                            Map::kTransitionsOrPrototypeInfoOffset);
    1022             :     }
    1023             :   }
    1024      137697 :   DescriptorArray descriptors = map->instance_descriptors();
    1025      137697 :   TagObject(descriptors, "(map descriptors)");
    1026             :   SetInternalReference(entry, "descriptors", descriptors,
    1027      137697 :                        Map::kDescriptorsOffset);
    1028      275394 :   SetInternalReference(entry, "prototype", map->prototype(),
    1029      137697 :                        Map::kPrototypeOffset);
    1030             :   if (FLAG_unbox_double_fields) {
    1031      275394 :     SetInternalReference(entry, "layout_descriptor", map->layout_descriptor(),
    1032      137697 :                          Map::kLayoutDescriptorOffset);
    1033             :   }
    1034             :   Object constructor_or_backpointer = map->constructor_or_backpointer();
    1035      137697 :   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      135533 :   } 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      135533 :                          Map::kConstructorOrBackPointerOffset);
    1047             :   }
    1048      137697 :   TagObject(map->dependent_code(), "(dependent code)");
    1049      275394 :   SetInternalReference(entry, "dependent_code", map->dependent_code(),
    1050      137697 :                        Map::kDependentCodeOffset);
    1051      137697 : }
    1052             : 
    1053      290344 : void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
    1054             :     HeapEntry* entry, SharedFunctionInfo shared) {
    1055      290344 :   String shared_name = shared->DebugName();
    1056             :   const char* name = nullptr;
    1057      580688 :   if (shared_name != ReadOnlyRoots(heap_).empty_string()) {
    1058      270719 :     name = names_->GetName(shared_name);
    1059      270719 :     TagObject(shared->GetCode(), names_->GetFormatted("(code for %s)", name));
    1060             :   } else {
    1061       58875 :     TagObject(shared->GetCode(),
    1062       19625 :               names_->GetFormatted(
    1063       58875 :                   "(%s code)", Code::Kind2String(shared->GetCode()->kind())));
    1064             :   }
    1065             : 
    1066      290344 :   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      290344 :                        SharedFunctionInfo::kNameOrScopeInfoOffset);
    1072             :   SetInternalReference(entry, "script_or_debug_info",
    1073             :                        shared->script_or_debug_info(),
    1074      290344 :                        SharedFunctionInfo::kScriptOrDebugInfoOffset);
    1075             :   SetInternalReference(entry, "function_data", shared->function_data(),
    1076      290344 :                        SharedFunctionInfo::kFunctionDataOffset);
    1077             :   SetInternalReference(
    1078             :       entry, "raw_outer_scope_info_or_feedback_metadata",
    1079      580688 :       shared->raw_outer_scope_info_or_feedback_metadata(),
    1080      290344 :       SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset);
    1081      290344 : }
    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        8646 :   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       28431 : void V8HeapExplorer::ExtractAccessorPairReferences(HeapEntry* entry,
    1110             :                                                    AccessorPair accessors) {
    1111             :   SetInternalReference(entry, "getter", accessors->getter(),
    1112       28431 :                        AccessorPair::kGetterOffset);
    1113             :   SetInternalReference(entry, "setter", accessors->setter(),
    1114       28431 :                        AccessorPair::kSetterOffset);
    1115       28431 : }
    1116             : 
    1117      605756 : void V8HeapExplorer::TagBuiltinCodeObject(Code code, const char* name) {
    1118      605756 :   TagObject(code, names_->GetFormatted("(%s builtin)", name));
    1119      605756 : }
    1120             : 
    1121      599609 : void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code code) {
    1122      599609 :   TagObject(code->relocation_info(), "(code relocation info)");
    1123     1199218 :   SetInternalReference(entry, "relocation_info", code->relocation_info(),
    1124      599609 :                        Code::kRelocationInfoOffset);
    1125      599609 :   TagObject(code->deoptimization_data(), "(code deopt data)");
    1126             :   SetInternalReference(entry, "deoptimization_data",
    1127     1199218 :                        code->deoptimization_data(),
    1128      599609 :                        Code::kDeoptimizationDataOffset);
    1129      599609 :   TagObject(code->source_position_table(), "(source position table)");
    1130             :   SetInternalReference(entry, "source_position_table",
    1131             :                        code->source_position_table(),
    1132      599609 :                        Code::kSourcePositionTableOffset);
    1133      599609 : }
    1134             : 
    1135           0 : void V8HeapExplorer::ExtractCellReferences(HeapEntry* entry, Cell cell) {
    1136        2677 :   SetInternalReference(entry, "value", cell->value(), Cell::kValueOffset);
    1137           0 : }
    1138             : 
    1139       34485 : void V8HeapExplorer::ExtractFeedbackCellReferences(HeapEntry* entry,
    1140             :                                                    FeedbackCell feedback_cell) {
    1141       34485 :   TagObject(feedback_cell, "(feedback cell)");
    1142       68970 :   SetInternalReference(entry, "value", feedback_cell->value(),
    1143       34485 :                        FeedbackCell::kValueOffset);
    1144       34485 : }
    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       56876 :   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          32 :   SetInternalReference(entry, "dependent_code", site->dependent_code(),
    1164          16 :                        AllocationSite::kDependentCodeOffset);
    1165          16 : }
    1166             : 
    1167           0 : void V8HeapExplorer::ExtractArrayBoilerplateDescriptionReferences(
    1168             :     HeapEntry* entry, ArrayBoilerplateDescription value) {
    1169          50 :   SetInternalReference(entry, "constant_elements", value->constant_elements(),
    1170          25 :                        ArrayBoilerplateDescription::kConstantElementsOffset);
    1171           0 : }
    1172             : 
    1173          15 : 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          10 :     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          20 :   SetInternalReference(entry, "function", generator->function(),
    1211          10 :                        JSGeneratorObject::kFunctionOffset);
    1212          20 :   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          20 :                        generator->parameters_and_registers(),
    1218          10 :                        JSGeneratorObject::kParametersAndRegistersOffset);
    1219          10 : }
    1220             : 
    1221       10408 : void V8HeapExplorer::ExtractFixedArrayReferences(HeapEntry* entry,
    1222             :                                                  FixedArray array) {
    1223     5668204 :   for (int i = 0, l = array->length(); i < l; ++i) {
    1224             :     DCHECK(!HasWeakHeapObjectTag(array->get(i)));
    1225     2828898 :     SetInternalReference(entry, i, array->get(i), array->OffsetOfElementAt(i));
    1226             :   }
    1227       10408 : }
    1228             : 
    1229         448 : void V8HeapExplorer::ExtractFeedbackVectorReferences(
    1230             :     HeapEntry* entry, FeedbackVector feedback_vector) {
    1231             :   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       80777 : void V8HeapExplorer::ExtractDescriptorArrayReferences(HeapEntry* entry,
    1240             :                                                       DescriptorArray array) {
    1241      161554 :   SetInternalReference(entry, "enum_cache", array->enum_cache(),
    1242       80777 :                        DescriptorArray::kEnumCacheOffset);
    1243             :   MaybeObjectSlot start = MaybeObjectSlot(array->GetDescriptorSlot(0));
    1244             :   MaybeObjectSlot end = MaybeObjectSlot(
    1245       80777 :       array->GetDescriptorSlot(array->number_of_all_descriptors()));
    1246     2708921 :   for (int i = 0; start + i < end; ++i) {
    1247             :     MaybeObjectSlot slot = start + i;
    1248     2628144 :     int offset = static_cast<int>(slot.address() - array->address());
    1249             :     MaybeObject object = *slot;
    1250     1314072 :     HeapObject heap_object;
    1251     1314072 :     if (object->GetHeapObjectIfWeak(&heap_object)) {
    1252        4167 :       SetWeakReference(entry, i, heap_object, offset);
    1253     1309905 :     } else if (object->GetHeapObjectIfStrong(&heap_object)) {
    1254      566545 :       SetInternalReference(entry, i, heap_object, offset);
    1255             :     }
    1256             :   }
    1257       80777 : }
    1258             : 
    1259             : template <typename T>
    1260        6613 : void V8HeapExplorer::ExtractWeakArrayReferences(int header_size,
    1261             :                                                 HeapEntry* entry, T array) {
    1262      680243 :   for (int i = 0; i < array->length(); ++i) {
    1263             :     MaybeObject object = array->Get(i);
    1264      336815 :     HeapObject heap_object;
    1265      336815 :     if (object->GetHeapObjectIfWeak(&heap_object)) {
    1266      294241 :       SetWeakReference(entry, i, heap_object, header_size + i * kTaggedSize);
    1267       42574 :     } else if (object->GetHeapObjectIfStrong(&heap_object)) {
    1268       35306 :       SetInternalReference(entry, i, heap_object,
    1269             :                            header_size + i * kTaggedSize);
    1270             :     }
    1271             :   }
    1272        6613 : }
    1273             : 
    1274      423943 : void V8HeapExplorer::ExtractPropertyReferences(JSObject js_obj,
    1275             :                                                HeapEntry* entry) {
    1276             :   Isolate* isolate = js_obj->GetIsolate();
    1277      423943 :   if (js_obj->HasFastProperties()) {
    1278      423370 :     DescriptorArray descs = js_obj->map()->instance_descriptors();
    1279             :     int real_size = js_obj->map()->NumberOfOwnDescriptors();
    1280     2489716 :     for (int i = 0; i < real_size; i++) {
    1281     1033173 :       PropertyDetails details = descs->GetDetails(i);
    1282     1033173 :       switch (details.location()) {
    1283             :         case kField: {
    1284             :           Representation r = details.representation();
    1285      294706 :           if (r.IsSmi() || r.IsDouble()) break;
    1286             : 
    1287      266386 :           Name k = descs->GetKey(i);
    1288      266386 :           FieldIndex field_index = FieldIndex::ForDescriptor(js_obj->map(), i);
    1289      266386 :           Object value = js_obj->RawFastPropertyAt(field_index);
    1290             :           int field_offset =
    1291      266386 :               field_index.is_inobject() ? field_index.offset() : -1;
    1292             : 
    1293             :           SetDataOrAccessorPropertyReference(details.kind(), entry, k, value,
    1294      266386 :                                              nullptr, field_offset);
    1295      266386 :           break;
    1296             :         }
    1297             :         case kDescriptor:
    1298             :           SetDataOrAccessorPropertyReference(details.kind(), entry,
    1299             :                                              descs->GetKey(i),
    1300      738467 :                                              descs->GetStrongValue(i));
    1301      738467 :           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             :         JSGlobalObject::cast(js_obj)->global_dictionary();
    1308             :     int length = dictionary->Capacity();
    1309             :     ReadOnlyRoots roots(isolate);
    1310      101001 :     for (int i = 0; i < length; ++i) {
    1311       76886 :       if (!dictionary->IsKey(roots, dictionary->KeyAt(i))) continue;
    1312             :       PropertyCell cell = dictionary->CellAt(i);
    1313       23722 :       Name name = cell->name();
    1314       23722 :       Object value = cell->value();
    1315             :       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             :     int length = dictionary->Capacity();
    1321             :     ReadOnlyRoots roots(isolate);
    1322        4380 :     for (int i = 0; i < length; ++i) {
    1323             :       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      423943 : }
    1332             : 
    1333      738482 : void V8HeapExplorer::ExtractAccessorPairProperty(HeapEntry* entry, Name key,
    1334             :                                                  Object callback_obj,
    1335             :                                                  int field_offset) {
    1336      738482 :   if (!callback_obj->IsAccessorPair()) return;
    1337             :   AccessorPair accessors = AccessorPair::cast(callback_obj);
    1338       28431 :   SetPropertyReference(entry, key, accessors, nullptr, field_offset);
    1339             :   Object getter = accessors->getter();
    1340       28431 :   if (!getter->IsOddball()) {
    1341       28421 :     SetPropertyReference(entry, key, getter, "get %s");
    1342             :   }
    1343             :   Object setter = accessors->setter();
    1344       28431 :   if (!setter->IsOddball()) {
    1345        9002 :     SetPropertyReference(entry, key, setter, "set %s");
    1346             :   }
    1347             : }
    1348             : 
    1349      423943 : void V8HeapExplorer::ExtractElementReferences(JSObject js_obj,
    1350             :                                               HeapEntry* entry) {
    1351             :   ReadOnlyRoots roots = js_obj->GetReadOnlyRoots();
    1352      423943 :   if (js_obj->HasObjectElements()) {
    1353             :     FixedArray elements = FixedArray::cast(js_obj->elements());
    1354             :     int length = js_obj->IsJSArray()
    1355             :                      ? Smi::ToInt(JSArray::cast(js_obj)->length())
    1356      423152 :                      : elements->length();
    1357      683594 :     for (int i = 0; i < length; ++i) {
    1358      130221 :       if (!elements->get(i)->IsTheHole(roots)) {
    1359      130131 :         SetElementReference(entry, i, elements->get(i));
    1360             :       }
    1361             :     }
    1362         791 :   } else if (js_obj->HasDictionaryElements()) {
    1363             :     NumberDictionary dictionary = js_obj->element_dictionary();
    1364             :     int length = dictionary->Capacity();
    1365        1179 :     for (int i = 0; i < length; ++i) {
    1366             :       Object k = dictionary->KeyAt(i);
    1367         393 :       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      423943 : }
    1374             : 
    1375      423943 : void V8HeapExplorer::ExtractInternalReferences(JSObject js_obj,
    1376             :                                                HeapEntry* entry) {
    1377      423943 :   int length = js_obj->GetEmbedderFieldCount();
    1378      424133 :   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      423943 : }
    1383             : 
    1384      141847 : JSFunction V8HeapExplorer::GetConstructor(JSReceiver receiver) {
    1385             :   Isolate* isolate = receiver->GetIsolate();
    1386             :   DisallowHeapAllocation no_gc;
    1387             :   HandleScope scope(isolate);
    1388             :   MaybeHandle<JSFunction> maybe_constructor =
    1389      141847 :       JSReceiver::GetConstructor(handle(receiver, isolate));
    1390             : 
    1391      141847 :   if (maybe_constructor.is_null()) return JSFunction();
    1392             : 
    1393             :   return *maybe_constructor.ToHandleChecked();
    1394             : }
    1395             : 
    1396      141464 : String V8HeapExplorer::GetConstructorName(JSObject object) {
    1397             :   Isolate* isolate = object->GetIsolate();
    1398      141464 :   if (object->IsJSFunction()) return ReadOnlyRoots(isolate).closure_string();
    1399             :   DisallowHeapAllocation no_gc;
    1400             :   HandleScope scope(isolate);
    1401      282928 :   return *JSReceiver::GetConstructorName(handle(object, isolate));
    1402             : }
    1403             : 
    1404           0 : HeapEntry* V8HeapExplorer::GetEntry(Object obj) {
    1405    22306538 :   return obj->IsHeapObject() ? generator_->FindOrAddEntry(
    1406             :                                    reinterpret_cast<void*>(obj.ptr()), this)
    1407    45279036 :                              : nullptr;
    1408             : }
    1409             : 
    1410         398 : 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     1453058 :   void VisitRootPointer(Root root, const char* description,
    1418             :                         FullObjectSlot object) override {
    1419     1453058 :     if (root == Root::kBuiltins) {
    1420      605756 :       explorer_->TagBuiltinCodeObject(Code::cast(*object), description);
    1421             :     }
    1422     1453058 :     explorer_->SetGcSubrootReference(root, description, visiting_weak_roots_,
    1423     1453058 :                                      *object);
    1424     1453058 :   }
    1425             : 
    1426        4318 :   void VisitRootPointers(Root root, const char* description,
    1427             :                          FullObjectSlot start, FullObjectSlot end) override {
    1428      253857 :     for (FullObjectSlot p = start; p < end; ++p) {
    1429      245221 :       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       19502 :   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     9179569 :   for (HeapObject obj = iterator.next(); !obj.is_null();
    1462     3059591 :        obj = iterator.next(), progress_->ProgressStep()) {
    1463     3092330 :     if (interrupted) continue;
    1464             : 
    1465     3026852 :     size_t max_pointer = obj->Size() / kTaggedSize;
    1466     3026852 :     if (max_pointer > visited_fields_.size()) {
    1467             :       // Clear the current bits.
    1468        2368 :       std::vector<bool>().swap(visited_fields_);
    1469             :       // Reallocate to right size.
    1470        2368 :       visited_fields_.resize(max_pointer, false);
    1471             :     }
    1472             : 
    1473             :     HeapEntry* entry = GetEntry(obj);
    1474     3026852 :     ExtractReferences(entry, obj);
    1475     3026852 :     SetInternalReference(entry, "map", obj->map(), HeapObject::kMapOffset);
    1476             :     // Extract unvisited fields as hidden references and restore tags
    1477             :     // of visited fields.
    1478             :     IndexedReferencesExtractor refs_extractor(this, obj, entry);
    1479     3026852 :     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     3026852 :     ExtractLocation(entry, obj);
    1488             : 
    1489     3026852 :     if (!progress_->ProgressReport(false)) interrupted = true;
    1490             :   }
    1491             : 
    1492         398 :   generator_ = nullptr;
    1493         796 :   return interrupted ? false : progress_->ProgressReport(true);
    1494             : }
    1495             : 
    1496    19065031 : bool V8HeapExplorer::IsEssentialObject(Object object) {
    1497    19065031 :   ReadOnlyRoots roots(heap_);
    1498    34914448 :   return object->IsHeapObject() && !object->IsOddball() &&
    1499    14650315 :          object != roots.empty_byte_array() &&
    1500    11872830 :          object != roots.empty_fixed_array() &&
    1501    11540168 :          object != roots.empty_weak_fixed_array() &&
    1502    11429492 :          object != roots.empty_descriptor_array() &&
    1503    22846605 :          object != roots.fixed_array_map() && object != roots.cell_map() &&
    1504    11393526 :          object != roots.global_property_cell_map() &&
    1505    11103182 :          object != roots.shared_function_info_map() &&
    1506    11103182 :          object != roots.free_space_map() &&
    1507    30166983 :          object != roots.one_pointer_filler_map() &&
    1508    19065031 :          object != roots.two_pointer_filler_map();
    1509             : }
    1510             : 
    1511     1000324 : bool V8HeapExplorer::IsEssentialHiddenReference(Object parent,
    1512             :                                                 int field_offset) {
    1513     1000324 :   if (parent->IsAllocationSite() &&
    1514             :       field_offset == AllocationSite::kWeakNextOffset)
    1515             :     return false;
    1516     1000324 :   if (parent->IsCodeDataContainer() &&
    1517             :       field_offset == CodeDataContainer::kNextCodeLinkOffset)
    1518             :     return false;
    1519     1000288 :   if (parent->IsContext() &&
    1520             :       field_offset == Context::OffsetOfElementAt(Context::NEXT_CONTEXT_LINK))
    1521             :     return false;
    1522     1000288 :   return true;
    1523             : }
    1524             : 
    1525       33587 : void V8HeapExplorer::SetContextReference(HeapEntry* parent_entry,
    1526             :                                          String reference_name,
    1527             :                                          Object child_obj, int field_offset) {
    1528             :   HeapEntry* child_entry = GetEntry(child_obj);
    1529       33587 :   if (child_entry == nullptr) return;
    1530       33577 :   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    13243876 :   if (offset < 0) return;
    1537    12528771 :   int index = offset / kTaggedSize;
    1538             :   DCHECK(!visited_fields_[index]);
    1539    12528771 :   visited_fields_[index] = true;
    1540             : }
    1541             : 
    1542          10 : void V8HeapExplorer::SetNativeBindReference(HeapEntry* parent_entry,
    1543             :                                             const char* reference_name,
    1544             :                                             Object child_obj) {
    1545             :   HeapEntry* child_entry = GetEntry(child_obj);
    1546          10 :   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             :   HeapEntry* child_entry = GetEntry(child_obj);
    1554      130131 :   if (child_entry == nullptr) return;
    1555             :   parent_entry->SetIndexedReference(HeapGraphEdge::kElement, index,
    1556             :                                     child_entry);
    1557             : }
    1558             : 
    1559     9327460 : void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry,
    1560             :                                           const char* reference_name,
    1561             :                                           Object child_obj, int field_offset) {
    1562             :   HeapEntry* child_entry = GetEntry(child_obj);
    1563     9327460 :   if (child_entry == nullptr) return;
    1564     8932002 :   if (IsEssentialObject(child_obj)) {
    1565             :     parent_entry->SetNamedReference(HeapGraphEdge::kInternal, reference_name,
    1566             :                                     child_entry);
    1567             :   }
    1568             :   MarkVisitedField(field_offset);
    1569             : }
    1570             : 
    1571     3430844 : void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry, int index,
    1572             :                                           Object child_obj, int field_offset) {
    1573             :   HeapEntry* child_entry = GetEntry(child_obj);
    1574     3430844 :   if (child_entry == nullptr) return;
    1575     3168978 :   if (IsEssentialObject(child_obj)) {
    1576     1244382 :     parent_entry->SetNamedReference(HeapGraphEdge::kInternal,
    1577     1244382 :                                     names_->GetName(index), child_entry);
    1578             :   }
    1579             :   MarkVisitedField(field_offset);
    1580             : }
    1581             : 
    1582     1903452 : 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             :   HeapEntry* child_entry = GetEntry(child_obj);
    1587     2903776 :   if (child_entry != nullptr && IsEssentialObject(child_obj) &&
    1588     1000324 :       IsEssentialHiddenReference(parent_obj, field_offset)) {
    1589             :     parent_entry->SetIndexedReference(HeapGraphEdge::kHidden, index,
    1590             :                                       child_entry);
    1591             :   }
    1592     1903452 : }
    1593             : 
    1594         979 : void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry,
    1595             :                                       const char* reference_name,
    1596             :                                       Object child_obj, int field_offset) {
    1597             :   HeapEntry* child_entry = GetEntry(child_obj);
    1598         979 :   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      298528 : void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry, int index,
    1607             :                                       Object child_obj, int field_offset) {
    1608             :   HeapEntry* child_entry = GetEntry(child_obj);
    1609      298528 :   if (child_entry == nullptr) return;
    1610      298528 :   if (IsEssentialObject(child_obj)) {
    1611      298438 :     parent_entry->SetNamedReference(
    1612      298438 :         HeapGraphEdge::kWeak, names_->GetFormatted("%d", index), child_entry);
    1613             :   }
    1614             :   MarkVisitedField(field_offset);
    1615             : }
    1616             : 
    1617     1029265 : 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     1029265 :   if (kind == kAccessor) {
    1621             :     ExtractAccessorPairProperty(parent_entry, reference_name, child_obj,
    1622      738482 :                                 field_offset);
    1623             :   } else {
    1624             :     SetPropertyReference(parent_entry, reference_name, child_obj,
    1625      290783 :                          name_format_string, field_offset);
    1626             :   }
    1627     1029265 : }
    1628             : 
    1629      815354 : void V8HeapExplorer::SetPropertyReference(HeapEntry* parent_entry,
    1630             :                                           Name reference_name, Object child_obj,
    1631             :                                           const char* name_format_string,
    1632             :                                           int field_offset) {
    1633             :   HeapEntry* child_entry = GetEntry(child_obj);
    1634      815354 :   if (child_entry == nullptr) return;
    1635             :   HeapGraphEdge::Type type =
    1636      781550 :       reference_name->IsSymbol() || String::cast(reference_name)->length() > 0
    1637             :           ? HeapGraphEdge::kProperty
    1638      809812 :           : HeapGraphEdge::kInternal;
    1639             :   const char* name =
    1640       37423 :       name_format_string != nullptr && reference_name->IsString()
    1641       33886 :           ? names_->GetFormatted(
    1642             :                 name_format_string,
    1643      877584 :                 String::cast(reference_name)
    1644      877584 :                     ->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)
    1645             :                     .get())
    1646     1619624 :           : 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             :   HeapEntry* child_entry = GetEntry(child_obj);
    1659             :   DCHECK_NOT_NULL(child_entry);
    1660         398 :   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     1453058 : void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description,
    1670             :                                            bool is_weak, Object child_obj) {
    1671             :   HeapEntry* child_entry = GetEntry(child_obj);
    1672     2905718 :   if (child_entry == nullptr) return;
    1673     1449987 :   const char* name = GetStrongGcSubrootName(child_obj);
    1674             :   HeapGraphEdge::Type edge_type =
    1675     1449987 :       is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kInternal;
    1676     1449987 :   if (name != nullptr) {
    1677      239062 :     snapshot_->gc_subroot(root)->SetNamedReference(edge_type, name,
    1678             :                                                    child_entry);
    1679             :   } else {
    1680     1210925 :     snapshot_->gc_subroot(root)->SetNamedAutoIndexReference(
    1681     1210925 :         edge_type, description, child_entry, names_);
    1682             :   }
    1683             : 
    1684             :   // For full heap snapshots we do not emit user roots but rather rely on
    1685             :   // regular GC roots to retain objects.
    1686             :   if (FLAG_raw_heap_snapshots) return;
    1687             : 
    1688             :   // Add a shortcut to JS global object reference at snapshot root.
    1689             :   // That allows the user to easily find global objects. They are
    1690             :   // also used as starting points in distance calculations.
    1691     2899919 :   if (is_weak || !child_obj->IsNativeContext()) return;
    1692             : 
    1693        1952 :   JSGlobalObject global = Context::cast(child_obj)->global_object();
    1694        1952 :   if (!global->IsJSGlobalObject()) return;
    1695             : 
    1696        1952 :   if (!user_roots_.insert(global).second) return;
    1697             : 
    1698         398 :   SetUserGlobalReference(global);
    1699             : }
    1700             : 
    1701     1449987 : const char* V8HeapExplorer::GetStrongGcSubrootName(Object object) {
    1702     1449987 :   if (strong_gc_subroot_names_.empty()) {
    1703         398 :     Isolate* isolate = Isolate::FromHeap(heap_);
    1704             :     for (RootIndex root_index = RootIndex::kFirstStrongOrReadOnlyRoot;
    1705      235218 :          root_index <= RootIndex::kLastStrongOrReadOnlyRoot; ++root_index) {
    1706      234820 :       const char* name = RootsTable::name(root_index);
    1707      469640 :       strong_gc_subroot_names_.emplace(isolate->root(root_index), name);
    1708             :     }
    1709         398 :     CHECK(!strong_gc_subroot_names_.empty());
    1710             :   }
    1711             :   auto it = strong_gc_subroot_names_.find(object);
    1712     1449987 :   return it != strong_gc_subroot_names_.end() ? it->second : nullptr;
    1713             : }
    1714             : 
    1715     4761092 : void V8HeapExplorer::TagObject(Object obj, const char* tag) {
    1716     4761092 :   if (IsEssentialObject(obj)) {
    1717             :     HeapEntry* entry = GetEntry(obj);
    1718     2551725 :     if (entry->name()[0] == '\0') {
    1719             :       entry->set_name(tag);
    1720             :     }
    1721             :   }
    1722     4761092 : }
    1723             : 
    1724        1194 : class GlobalObjectsEnumerator : public RootVisitor {
    1725             :  public:
    1726         603 :   void VisitRootPointers(Root root, const char* description,
    1727             :                          FullObjectSlot start, FullObjectSlot end) override {
    1728        1809 :     for (FullObjectSlot p = start; p < end; ++p) {
    1729         603 :       if (!(*p)->IsNativeContext()) continue;
    1730         423 :       JSObject proxy = Context::cast(*p)->global_proxy();
    1731         423 :       if (!proxy->IsJSGlobalProxy()) continue;
    1732             :       Object global = proxy->map()->prototype();
    1733         423 :       if (!global->IsJSGlobalObject()) continue;
    1734         846 :       objects_.push_back(Handle<JSGlobalObject>(JSGlobalObject::cast(global),
    1735             :                                                 proxy->GetIsolate()));
    1736             :     }
    1737         603 :   }
    1738        1194 :   int count() const { return static_cast<int>(objects_.size()); }
    1739             :   Handle<JSGlobalObject>& at(int i) { return objects_[i]; }
    1740             : 
    1741             :  private:
    1742             :   std::vector<Handle<JSGlobalObject>> objects_;
    1743             : };
    1744             : 
    1745             : 
    1746             : // Modifies heap. Must not be run during heap traversal.
    1747         398 : void V8HeapExplorer::TagGlobalObjects() {
    1748         398 :   Isolate* isolate = Isolate::FromHeap(heap_);
    1749             :   HandleScope scope(isolate);
    1750             :   GlobalObjectsEnumerator enumerator;
    1751         398 :   isolate->global_handles()->IterateAllRoots(&enumerator);
    1752         398 :   std::vector<const char*> urls(enumerator.count());
    1753        1244 :   for (int i = 0, l = enumerator.count(); i < l; ++i) {
    1754         846 :     urls[i] = global_object_name_resolver_
    1755             :                   ? global_object_name_resolver_->GetName(Utils::ToLocal(
    1756          55 :                         Handle<JSObject>::cast(enumerator.at(i))))
    1757         478 :                   : nullptr;
    1758             :   }
    1759             : 
    1760             :   DisallowHeapAllocation no_allocation;
    1761        1244 :   for (int i = 0, l = enumerator.count(); i < l; ++i) {
    1762         956 :     if (urls[i]) objects_tags_.emplace(*enumerator.at(i), urls[i]);
    1763             :   }
    1764         398 : }
    1765             : 
    1766         140 : class EmbedderGraphImpl : public EmbedderGraph {
    1767             :  public:
    1768             :   struct Edge {
    1769             :     Node* from;
    1770             :     Node* to;
    1771             :     const char* name;
    1772             :   };
    1773             : 
    1774         100 :   class V8NodeImpl : public Node {
    1775             :    public:
    1776          50 :     explicit V8NodeImpl(Object object) : object_(object) {}
    1777             :     Object GetObject() { return object_; }
    1778             : 
    1779             :     // Node overrides.
    1780          75 :     bool IsEmbedderNode() override { return false; }
    1781           0 :     const char* Name() override {
    1782             :       // The name should be retrieved via GetObject().
    1783           0 :       UNREACHABLE();
    1784             :       return "";
    1785             :     }
    1786           0 :     size_t SizeInBytes() override {
    1787             :       // The size should be retrieved via GetObject().
    1788           0 :       UNREACHABLE();
    1789             :       return 0;
    1790             :     }
    1791             : 
    1792             :    private:
    1793             :     Object object_;
    1794             :   };
    1795             : 
    1796          50 :   Node* V8Node(const v8::Local<v8::Value>& value) final {
    1797             :     Handle<Object> object = v8::Utils::OpenHandle(*value);
    1798             :     DCHECK(!object.is_null());
    1799         100 :     return AddNode(std::unique_ptr<Node>(new V8NodeImpl(*object)));
    1800             :   }
    1801             : 
    1802          90 :   Node* AddNode(std::unique_ptr<Node> node) final {
    1803             :     Node* result = node.get();
    1804         140 :     nodes_.push_back(std::move(node));
    1805          90 :     return result;
    1806             :   }
    1807             : 
    1808         110 :   void AddEdge(Node* from, Node* to, const char* name) final {
    1809         220 :     edges_.push_back({from, to, name});
    1810         110 :   }
    1811             : 
    1812             :   const std::vector<std::unique_ptr<Node>>& nodes() { return nodes_; }
    1813             :   const std::vector<Edge>& edges() { return edges_; }
    1814             : 
    1815             :  private:
    1816             :   std::vector<std::unique_ptr<Node>> nodes_;
    1817             :   std::vector<Edge> edges_;
    1818             : };
    1819             : 
    1820         796 : class EmbedderGraphEntriesAllocator : public HeapEntriesAllocator {
    1821             :  public:
    1822             :   explicit EmbedderGraphEntriesAllocator(HeapSnapshot* snapshot)
    1823             :       : snapshot_(snapshot),
    1824             :         names_(snapshot_->profiler()->names()),
    1825        1194 :         heap_object_map_(snapshot_->profiler()->heap_object_map()) {}
    1826             :   HeapEntry* AllocateEntry(HeapThing ptr) override;
    1827             : 
    1828             :  private:
    1829             :   HeapSnapshot* snapshot_;
    1830             :   StringsStorage* names_;
    1831             :   HeapObjectsMap* heap_object_map_;
    1832             : };
    1833             : 
    1834             : namespace {
    1835             : 
    1836          90 : const char* EmbedderGraphNodeName(StringsStorage* names,
    1837             :                                   EmbedderGraphImpl::Node* node) {
    1838          90 :   const char* prefix = node->NamePrefix();
    1839           5 :   return prefix ? names->GetFormatted("%s %s", prefix, node->Name())
    1840          95 :                 : names->GetCopy(node->Name());
    1841             : }
    1842             : 
    1843             : HeapEntry::Type EmbedderGraphNodeType(EmbedderGraphImpl::Node* node) {
    1844          90 :   return node->IsRootNode() ? HeapEntry::kSynthetic : HeapEntry::kNative;
    1845             : }
    1846             : 
    1847             : // Merges the names of an embedder node and its wrapper node.
    1848             : // If the wrapper node name contains a tag suffix (part after '/') then the
    1849             : // result is the embedder node name concatenated with the tag suffix.
    1850             : // Otherwise, the result is the embedder node name.
    1851          10 : const char* MergeNames(StringsStorage* names, const char* embedder_name,
    1852             :                        const char* wrapper_name) {
    1853             :   const char* suffix = strchr(wrapper_name, '/');
    1854             :   return suffix ? names->GetFormatted("%s %s", embedder_name, suffix)
    1855          10 :                 : embedder_name;
    1856             : }
    1857             : 
    1858             : }  // anonymous namespace
    1859             : 
    1860          80 : HeapEntry* EmbedderGraphEntriesAllocator::AllocateEntry(HeapThing ptr) {
    1861             :   EmbedderGraphImpl::Node* node =
    1862             :       reinterpret_cast<EmbedderGraphImpl::Node*>(ptr);
    1863             :   DCHECK(node->IsEmbedderNode());
    1864          80 :   size_t size = node->SizeInBytes();
    1865         160 :   return snapshot_->AddEntry(
    1866             :       EmbedderGraphNodeType(node), EmbedderGraphNodeName(names_, node),
    1867             :       static_cast<SnapshotObjectId>(reinterpret_cast<uintptr_t>(node) << 1),
    1868          80 :       static_cast<int>(size), 0);
    1869             : }
    1870             : 
    1871         398 : NativeObjectsExplorer::NativeObjectsExplorer(
    1872             :     HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress)
    1873             :     : isolate_(
    1874             :           Isolate::FromHeap(snapshot->profiler()->heap_object_map()->heap())),
    1875             :       snapshot_(snapshot),
    1876             :       names_(snapshot_->profiler()->names()),
    1877             :       embedder_graph_entries_allocator_(
    1878        1194 :           new EmbedderGraphEntriesAllocator(snapshot)) {}
    1879             : 
    1880         245 : HeapEntry* NativeObjectsExplorer::EntryForEmbedderGraphNode(
    1881             :     EmbedderGraphImpl::Node* node) {
    1882         245 :   EmbedderGraphImpl::Node* wrapper = node->WrapperNode();
    1883         245 :   if (wrapper) {
    1884             :     node = wrapper;
    1885             :   }
    1886         245 :   if (node->IsEmbedderNode()) {
    1887         170 :     return generator_->FindOrAddEntry(node,
    1888         170 :                                       embedder_graph_entries_allocator_.get());
    1889             :   } else {
    1890             :     EmbedderGraphImpl::V8NodeImpl* v8_node =
    1891             :         static_cast<EmbedderGraphImpl::V8NodeImpl*>(node);
    1892             :     Object object = v8_node->GetObject();
    1893          75 :     if (object->IsSmi()) return nullptr;
    1894          75 :     return generator_->FindEntry(
    1895             :         reinterpret_cast<void*>(Object::cast(object).ptr()));
    1896             :   }
    1897             : }
    1898             : 
    1899         393 : bool NativeObjectsExplorer::IterateAndExtractReferences(
    1900             :     HeapSnapshotGenerator* generator) {
    1901         393 :   generator_ = generator;
    1902             : 
    1903         786 :   if (FLAG_heap_profiler_use_embedder_graph &&
    1904         393 :       snapshot_->profiler()->HasBuildEmbedderGraphCallback()) {
    1905          70 :     v8::HandleScope scope(reinterpret_cast<v8::Isolate*>(isolate_));
    1906             :     DisallowHeapAllocation no_allocation;
    1907          35 :     EmbedderGraphImpl graph;
    1908          35 :     snapshot_->profiler()->BuildEmbedderGraph(isolate_, &graph);
    1909         175 :     for (const auto& node : graph.nodes()) {
    1910         140 :       if (node->IsRootNode()) {
    1911          15 :         snapshot_->root()->SetIndexedAutoIndexReference(
    1912          15 :             HeapGraphEdge::kElement, EntryForEmbedderGraphNode(node.get()));
    1913             :       }
    1914             :       // Adjust the name and the type of the V8 wrapper node.
    1915         140 :       auto wrapper = node->WrapperNode();
    1916         140 :       if (wrapper) {
    1917          10 :         HeapEntry* wrapper_entry = EntryForEmbedderGraphNode(wrapper);
    1918          10 :         wrapper_entry->set_name(
    1919             :             MergeNames(names_, EmbedderGraphNodeName(names_, node.get()),
    1920             :                        wrapper_entry->name()));
    1921             :         wrapper_entry->set_type(EmbedderGraphNodeType(node.get()));
    1922             :       }
    1923             :     }
    1924             :     // Fill edges of the graph.
    1925         145 :     for (const auto& edge : graph.edges()) {
    1926         110 :       HeapEntry* from = EntryForEmbedderGraphNode(edge.from);
    1927             :       // |from| and |to| can be nullptr if the corresponding node is a V8 node
    1928             :       // pointing to a Smi.
    1929         110 :       if (!from) continue;
    1930         110 :       HeapEntry* to = EntryForEmbedderGraphNode(edge.to);
    1931         110 :       if (!to) continue;
    1932         110 :       if (edge.name == nullptr) {
    1933         100 :         from->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, to);
    1934             :       } else {
    1935          10 :         from->SetNamedReference(HeapGraphEdge::kInternal,
    1936          10 :                                 names_->GetCopy(edge.name), to);
    1937             :       }
    1938             :     }
    1939             :   }
    1940         393 :   generator_ = nullptr;
    1941         393 :   return true;
    1942             : }
    1943             : 
    1944         398 : HeapSnapshotGenerator::HeapSnapshotGenerator(
    1945             :     HeapSnapshot* snapshot,
    1946             :     v8::ActivityControl* control,
    1947             :     v8::HeapProfiler::ObjectNameResolver* resolver,
    1948             :     Heap* heap)
    1949             :     : snapshot_(snapshot),
    1950             :       control_(control),
    1951             :       v8_heap_explorer_(snapshot_, this, resolver),
    1952             :       dom_explorer_(snapshot_, this),
    1953         796 :       heap_(heap) {
    1954         398 : }
    1955             : 
    1956             : namespace {
    1957             : class NullContextScope {
    1958             :  public:
    1959             :   explicit NullContextScope(Isolate* isolate)
    1960             :       : isolate_(isolate), prev_(isolate->context()) {
    1961             :     isolate_->set_context(Context());
    1962             :   }
    1963             :   ~NullContextScope() { isolate_->set_context(prev_); }
    1964             : 
    1965             :  private:
    1966             :   Isolate* isolate_;
    1967             :   Context prev_;
    1968             : };
    1969             : }  //  namespace
    1970             : 
    1971         398 : bool HeapSnapshotGenerator::GenerateSnapshot() {
    1972         398 :   v8_heap_explorer_.TagGlobalObjects();
    1973             : 
    1974             :   // TODO(1562) Profiler assumes that any object that is in the heap after
    1975             :   // full GC is reachable from the root when computing dominators.
    1976             :   // This is not true for weakly reachable objects.
    1977             :   // As a temporary solution we call GC twice.
    1978         398 :   heap_->PreciseCollectAllGarbage(Heap::kNoGCFlags,
    1979         398 :                                   GarbageCollectionReason::kHeapProfiler);
    1980         398 :   heap_->PreciseCollectAllGarbage(Heap::kNoGCFlags,
    1981         398 :                                   GarbageCollectionReason::kHeapProfiler);
    1982             : 
    1983         398 :   NullContextScope null_context_scope(Isolate::FromHeap(heap_));
    1984             : 
    1985             : #ifdef VERIFY_HEAP
    1986             :   Heap* debug_heap = heap_;
    1987             :   if (FLAG_verify_heap) {
    1988             :     debug_heap->Verify();
    1989             :   }
    1990             : #endif
    1991             : 
    1992             :   InitProgressCounter();
    1993             : 
    1994             : #ifdef VERIFY_HEAP
    1995             :   if (FLAG_verify_heap) {
    1996             :     debug_heap->Verify();
    1997             :   }
    1998             : #endif
    1999             : 
    2000         398 :   snapshot_->AddSyntheticRootEntries();
    2001             : 
    2002         398 :   if (!FillReferences()) return false;
    2003             : 
    2004         393 :   snapshot_->FillChildren();
    2005         393 :   snapshot_->RememberLastJSObjectId();
    2006             : 
    2007         393 :   progress_counter_ = progress_total_;
    2008         393 :   if (!ProgressReport(true)) return false;
    2009         393 :   return true;
    2010             : }
    2011             : 
    2012     3059591 : void HeapSnapshotGenerator::ProgressStep() {
    2013     3059591 :   ++progress_counter_;
    2014     3059591 : }
    2015             : 
    2016     3027638 : bool HeapSnapshotGenerator::ProgressReport(bool force) {
    2017             :   const int kProgressReportGranularity = 10000;
    2018     3027638 :   if (control_ != nullptr &&
    2019       65493 :       (force || progress_counter_ % kProgressReportGranularity == 0)) {
    2020          35 :     return control_->ReportProgressValue(progress_counter_, progress_total_) ==
    2021          35 :            v8::ActivityControl::kContinue;
    2022             :   }
    2023             :   return true;
    2024             : }
    2025             : 
    2026           0 : void HeapSnapshotGenerator::InitProgressCounter() {
    2027         398 :   if (control_ == nullptr) return;
    2028             :   // The +1 ensures that intermediate ProgressReport calls will never signal
    2029             :   // that the work is finished (i.e. progress_counter_ == progress_total_).
    2030             :   // Only the forced ProgressReport() at the end of GenerateSnapshot()
    2031             :   // should signal that the work is finished because signalling finished twice
    2032             :   // breaks the DevTools frontend.
    2033          15 :   progress_total_ = v8_heap_explorer_.EstimateObjectsCount() + 1;
    2034          15 :   progress_counter_ = 0;
    2035             : }
    2036             : 
    2037         398 : bool HeapSnapshotGenerator::FillReferences() {
    2038         791 :   return v8_heap_explorer_.IterateAndExtractReferences(this) &&
    2039         791 :          dom_explorer_.IterateAndExtractReferences(this);
    2040             : }
    2041             : 
    2042             : template<int bytes> struct MaxDecimalDigitsIn;
    2043             : template<> struct MaxDecimalDigitsIn<4> {
    2044             :   static const int kSigned = 11;
    2045             :   static const int kUnsigned = 10;
    2046             : };
    2047             : template<> struct MaxDecimalDigitsIn<8> {
    2048             :   static const int kSigned = 20;
    2049             :   static const int kUnsigned = 20;
    2050             : };
    2051             : 
    2052          35 : class OutputStreamWriter {
    2053             :  public:
    2054          35 :   explicit OutputStreamWriter(v8::OutputStream* stream)
    2055             :       : stream_(stream),
    2056          35 :         chunk_size_(stream->GetChunkSize()),
    2057             :         chunk_(chunk_size_),
    2058             :         chunk_pos_(0),
    2059         105 :         aborted_(false) {
    2060             :     DCHECK_GT(chunk_size_, 0);
    2061          35 :   }
    2062             :   bool aborted() { return aborted_; }
    2063             :   void AddCharacter(char c) {
    2064             :     DCHECK_NE(c, '\0');
    2065             :     DCHECK(chunk_pos_ < chunk_size_);
    2066     9625060 :     chunk_[chunk_pos_++] = c;
    2067     4812530 :     MaybeWriteChunk();
    2068             :   }
    2069             :   void AddString(const char* s) {
    2070      968995 :     AddSubstring(s, StrLength(s));
    2071             :   }
    2072      968995 :   void AddSubstring(const char* s, int n) {
    2073      968995 :     if (n <= 0) return;
    2074             :     DCHECK(static_cast<size_t>(n) <= strlen(s));
    2075      968995 :     const char* s_end = s + n;
    2076     2911235 :     while (s < s_end) {
    2077             :       int s_chunk_size =
    2078      971120 :           Min(chunk_size_ - chunk_pos_, static_cast<int>(s_end - s));
    2079             :       DCHECK_GT(s_chunk_size, 0);
    2080      971120 :       MemCopy(chunk_.start() + chunk_pos_, s, s_chunk_size);
    2081      971120 :       s += s_chunk_size;
    2082      971120 :       chunk_pos_ += s_chunk_size;
    2083      971120 :       MaybeWriteChunk();
    2084             :     }
    2085             :   }
    2086         105 :   void AddNumber(unsigned n) { AddNumberImpl<unsigned>(n, "%u"); }
    2087          30 :   void Finalize() {
    2088          30 :     if (aborted_) return;
    2089             :     DCHECK(chunk_pos_ < chunk_size_);
    2090          30 :     if (chunk_pos_ != 0) {
    2091             :       WriteChunk();
    2092             :     }
    2093          30 :     stream_->EndOfStream();
    2094             :   }
    2095             : 
    2096             :  private:
    2097             :   template<typename T>
    2098         105 :   void AddNumberImpl(T n, const char* format) {
    2099             :     // Buffer for the longest value plus trailing \0
    2100             :     static const int kMaxNumberSize =
    2101             :         MaxDecimalDigitsIn<sizeof(T)>::kUnsigned + 1;
    2102         105 :     if (chunk_size_ - chunk_pos_ >= kMaxNumberSize) {
    2103         105 :       int result = SNPrintF(
    2104         105 :           chunk_.SubVector(chunk_pos_, chunk_size_), format, n);
    2105             :       DCHECK_NE(result, -1);
    2106         105 :       chunk_pos_ += result;
    2107         105 :       MaybeWriteChunk();
    2108             :     } else {
    2109             :       EmbeddedVector<char, kMaxNumberSize> buffer;
    2110           0 :       int result = SNPrintF(buffer, format, n);
    2111             :       USE(result);
    2112             :       DCHECK_NE(result, -1);
    2113             :       AddString(buffer.start());
    2114             :     }
    2115         105 :   }
    2116     5783755 :   void MaybeWriteChunk() {
    2117             :     DCHECK(chunk_pos_ <= chunk_size_);
    2118     5783755 :     if (chunk_pos_ == chunk_size_) {
    2119             :       WriteChunk();
    2120             :     }
    2121     5783755 :   }
    2122             :   void WriteChunk() {
    2123        3144 :     if (aborted_) return;
    2124        3144 :     if (stream_->WriteAsciiChunk(chunk_.start(), chunk_pos_) ==
    2125           5 :         v8::OutputStream::kAbort) aborted_ = true;
    2126        3144 :     chunk_pos_ = 0;
    2127             :   }
    2128             : 
    2129             :   v8::OutputStream* stream_;
    2130             :   int chunk_size_;
    2131             :   ScopedVector<char> chunk_;
    2132             :   int chunk_pos_;
    2133             :   bool aborted_;
    2134             : };
    2135             : 
    2136             : 
    2137             : // type, name|index, to_node.
    2138             : const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3;
    2139             : // type, name, id, self_size, edge_count, trace_node_id.
    2140             : const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 6;
    2141             : 
    2142          35 : void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
    2143          35 :   if (AllocationTracker* allocation_tracker =
    2144          35 :       snapshot_->profiler()->allocation_tracker()) {
    2145           0 :     allocation_tracker->PrepareForSerialization();
    2146             :   }
    2147             :   DCHECK_NULL(writer_);
    2148          35 :   writer_ = new OutputStreamWriter(stream);
    2149          35 :   SerializeImpl();
    2150          70 :   delete writer_;
    2151          35 :   writer_ = nullptr;
    2152          35 : }
    2153             : 
    2154             : 
    2155          35 : void HeapSnapshotJSONSerializer::SerializeImpl() {
    2156             :   DCHECK_EQ(0, snapshot_->root()->index());
    2157          35 :   writer_->AddCharacter('{');
    2158          35 :   writer_->AddString("\"snapshot\":{");
    2159          35 :   SerializeSnapshot();
    2160          35 :   if (writer_->aborted()) return;
    2161             :   writer_->AddString("},\n");
    2162          35 :   writer_->AddString("\"nodes\":[");
    2163          35 :   SerializeNodes();
    2164          35 :   if (writer_->aborted()) return;
    2165             :   writer_->AddString("],\n");
    2166          30 :   writer_->AddString("\"edges\":[");
    2167          30 :   SerializeEdges();
    2168          30 :   if (writer_->aborted()) return;
    2169             :   writer_->AddString("],\n");
    2170             : 
    2171          30 :   writer_->AddString("\"trace_function_infos\":[");
    2172          30 :   SerializeTraceNodeInfos();
    2173          30 :   if (writer_->aborted()) return;
    2174             :   writer_->AddString("],\n");
    2175          30 :   writer_->AddString("\"trace_tree\":[");
    2176             :   SerializeTraceTree();
    2177          30 :   if (writer_->aborted()) return;
    2178             :   writer_->AddString("],\n");
    2179             : 
    2180          30 :   writer_->AddString("\"samples\":[");
    2181          30 :   SerializeSamples();
    2182          30 :   if (writer_->aborted()) return;
    2183             :   writer_->AddString("],\n");
    2184             : 
    2185          30 :   writer_->AddString("\"locations\":[");
    2186          30 :   SerializeLocations();
    2187          30 :   if (writer_->aborted()) return;
    2188             :   writer_->AddString("],\n");
    2189             : 
    2190          30 :   writer_->AddString("\"strings\":[");
    2191          30 :   SerializeStrings();
    2192          30 :   if (writer_->aborted()) return;
    2193             :   writer_->AddCharacter(']');
    2194          30 :   writer_->AddCharacter('}');
    2195          30 :   writer_->Finalize();
    2196             : }
    2197             : 
    2198             : 
    2199      887592 : int HeapSnapshotJSONSerializer::GetStringId(const char* s) {
    2200             :   base::HashMap::Entry* cache_entry =
    2201     1775184 :       strings_.LookupOrInsert(const_cast<char*>(s), StringHash(s));
    2202      887592 :   if (cache_entry->value == nullptr) {
    2203      201262 :     cache_entry->value = reinterpret_cast<void*>(next_string_id_++);
    2204             :   }
    2205      887592 :   return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value));
    2206             : }
    2207             : 
    2208             : 
    2209             : namespace {
    2210             : 
    2211             : template<size_t size> struct ToUnsigned;
    2212             : 
    2213             : template<> struct ToUnsigned<4> {
    2214             :   typedef uint32_t Type;
    2215             : };
    2216             : 
    2217             : template<> struct ToUnsigned<8> {
    2218             :   typedef uint64_t Type;
    2219             : };
    2220             : 
    2221             : }  // namespace
    2222             : 
    2223             : 
    2224             : template<typename T>
    2225             : static int utoa_impl(T value, const Vector<char>& buffer, int buffer_pos) {
    2226             :   STATIC_ASSERT(static_cast<T>(-1) > 0);  // Check that T is unsigned
    2227             :   int number_of_digits = 0;
    2228             :   T t = value;
    2229     9251958 :   do {
    2230     9251958 :     ++number_of_digits;
    2231             :   } while (t /= 10);
    2232             : 
    2233     3535614 :   buffer_pos += number_of_digits;
    2234             :   int result = buffer_pos;
    2235     9251958 :   do {
    2236     9251958 :     int last_digit = static_cast<int>(value % 10);
    2237    18503916 :     buffer[--buffer_pos] = '0' + last_digit;
    2238     9251958 :     value /= 10;
    2239             :   } while (value);
    2240             :   return result;
    2241             : }
    2242             : 
    2243             : 
    2244             : template<typename T>
    2245             : static int utoa(T value, const Vector<char>& buffer, int buffer_pos) {
    2246     1935230 :   typename ToUnsigned<sizeof(value)>::Type unsigned_value = value;
    2247             :   STATIC_ASSERT(sizeof(value) == sizeof(unsigned_value));
    2248             :   return utoa_impl(unsigned_value, buffer, buffer_pos);
    2249             : }
    2250             : 
    2251             : 
    2252      755597 : void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
    2253             :                                                bool first_edge) {
    2254             :   // The buffer needs space for 3 unsigned ints, 3 commas, \n and \0
    2255             :   static const int kBufferSize =
    2256             :       MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned * 3 + 3 + 2;  // NOLINT
    2257             :   EmbeddedVector<char, kBufferSize> buffer;
    2258             :   int edge_name_or_index = edge->type() == HeapGraphEdge::kElement
    2259      754839 :       || edge->type() == HeapGraphEdge::kHidden
    2260      834890 :       ? edge->index() : GetStringId(edge->name());
    2261             :   int buffer_pos = 0;
    2262      755597 :   if (!first_edge) {
    2263      755567 :     buffer[buffer_pos++] = ',';
    2264             :   }
    2265             :   buffer_pos = utoa(edge->type(), buffer, buffer_pos);
    2266     1511194 :   buffer[buffer_pos++] = ',';
    2267             :   buffer_pos = utoa(edge_name_or_index, buffer, buffer_pos);
    2268     1511194 :   buffer[buffer_pos++] = ',';
    2269             :   buffer_pos = utoa(to_node_index(edge->to()), buffer, buffer_pos);
    2270     1511194 :   buffer[buffer_pos++] = '\n';
    2271     1511194 :   buffer[buffer_pos++] = '\0';
    2272      755597 :   writer_->AddString(buffer.start());
    2273      755597 : }
    2274             : 
    2275          30 : void HeapSnapshotJSONSerializer::SerializeEdges() {
    2276          30 :   std::vector<HeapGraphEdge*>& edges = snapshot_->children();
    2277     1511224 :   for (size_t i = 0; i < edges.size(); ++i) {
    2278             :     DCHECK(i == 0 ||
    2279             :            edges[i - 1]->from()->index() <= edges[i]->from()->index());
    2280     1511194 :     SerializeEdge(edges[i], i == 0);
    2281      755597 :     if (writer_->aborted()) return;
    2282             :   }
    2283             : }
    2284             : 
    2285      211288 : void HeapSnapshotJSONSerializer::SerializeNode(const HeapEntry* entry) {
    2286             :   // The buffer needs space for 4 unsigned ints, 1 size_t, 5 commas, \n and \0
    2287             :   static const int kBufferSize =
    2288             :       5 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
    2289             :       + MaxDecimalDigitsIn<sizeof(size_t)>::kUnsigned  // NOLINT
    2290             :       + 6 + 1 + 1;
    2291             :   EmbeddedVector<char, kBufferSize> buffer;
    2292             :   int buffer_pos = 0;
    2293      211288 :   if (to_node_index(entry) != 0) {
    2294      211253 :     buffer[buffer_pos++] = ',';
    2295             :   }
    2296             :   buffer_pos = utoa(entry->type(), buffer, buffer_pos);
    2297      422576 :   buffer[buffer_pos++] = ',';
    2298      211288 :   buffer_pos = utoa(GetStringId(entry->name()), buffer, buffer_pos);
    2299      422576 :   buffer[buffer_pos++] = ',';
    2300             :   buffer_pos = utoa(entry->id(), buffer, buffer_pos);
    2301      422576 :   buffer[buffer_pos++] = ',';
    2302             :   buffer_pos = utoa(entry->self_size(), buffer, buffer_pos);
    2303      422576 :   buffer[buffer_pos++] = ',';
    2304             :   buffer_pos = utoa(entry->children_count(), buffer, buffer_pos);
    2305      422576 :   buffer[buffer_pos++] = ',';
    2306             :   buffer_pos = utoa(entry->trace_node_id(), buffer, buffer_pos);
    2307      422576 :   buffer[buffer_pos++] = '\n';
    2308      422576 :   buffer[buffer_pos++] = '\0';
    2309      211288 :   writer_->AddString(buffer.start());
    2310      211288 : }
    2311             : 
    2312          35 : void HeapSnapshotJSONSerializer::SerializeNodes() {
    2313          35 :   const std::deque<HeapEntry>& entries = snapshot_->entries();
    2314      211318 :   for (const HeapEntry& entry : entries) {
    2315      211288 :     SerializeNode(&entry);
    2316      211288 :     if (writer_->aborted()) return;
    2317             :   }
    2318             : }
    2319             : 
    2320          35 : void HeapSnapshotJSONSerializer::SerializeSnapshot() {
    2321          35 :   writer_->AddString("\"meta\":");
    2322             :   // The object describing node serialization layout.
    2323             :   // We use a set of macros to improve readability.
    2324             : 
    2325             : // clang-format off
    2326             : #define JSON_A(s) "[" s "]"
    2327             : #define JSON_O(s) "{" s "}"
    2328             : #define JSON_S(s) "\"" s "\""
    2329          35 :   writer_->AddString(JSON_O(
    2330             :     JSON_S("node_fields") ":" JSON_A(
    2331             :         JSON_S("type") ","
    2332             :         JSON_S("name") ","
    2333             :         JSON_S("id") ","
    2334             :         JSON_S("self_size") ","
    2335             :         JSON_S("edge_count") ","
    2336             :         JSON_S("trace_node_id")) ","
    2337             :     JSON_S("node_types") ":" JSON_A(
    2338             :         JSON_A(
    2339             :             JSON_S("hidden") ","
    2340             :             JSON_S("array") ","
    2341             :             JSON_S("string") ","
    2342             :             JSON_S("object") ","
    2343             :             JSON_S("code") ","
    2344             :             JSON_S("closure") ","
    2345             :             JSON_S("regexp") ","
    2346             :             JSON_S("number") ","
    2347             :             JSON_S("native") ","
    2348             :             JSON_S("synthetic") ","
    2349             :             JSON_S("concatenated string") ","
    2350             :             JSON_S("sliced string") ","
    2351             :             JSON_S("symbol") ","
    2352             :             JSON_S("bigint")) ","
    2353             :         JSON_S("string") ","
    2354             :         JSON_S("number") ","
    2355             :         JSON_S("number") ","
    2356             :         JSON_S("number") ","
    2357             :         JSON_S("number") ","
    2358             :         JSON_S("number")) ","
    2359             :     JSON_S("edge_fields") ":" JSON_A(
    2360             :         JSON_S("type") ","
    2361             :         JSON_S("name_or_index") ","
    2362             :         JSON_S("to_node")) ","
    2363             :     JSON_S("edge_types") ":" JSON_A(
    2364             :         JSON_A(
    2365             :             JSON_S("context") ","
    2366             :             JSON_S("element") ","
    2367             :             JSON_S("property") ","
    2368             :             JSON_S("internal") ","
    2369             :             JSON_S("hidden") ","
    2370             :             JSON_S("shortcut") ","
    2371             :             JSON_S("weak")) ","
    2372             :         JSON_S("string_or_number") ","
    2373             :         JSON_S("node")) ","
    2374             :     JSON_S("trace_function_info_fields") ":" JSON_A(
    2375             :         JSON_S("function_id") ","
    2376             :         JSON_S("name") ","
    2377             :         JSON_S("script_name") ","
    2378             :         JSON_S("script_id") ","
    2379             :         JSON_S("line") ","
    2380             :         JSON_S("column")) ","
    2381             :     JSON_S("trace_node_fields") ":" JSON_A(
    2382             :         JSON_S("id") ","
    2383             :         JSON_S("function_info_index") ","
    2384             :         JSON_S("count") ","
    2385             :         JSON_S("size") ","
    2386             :         JSON_S("children")) ","
    2387             :     JSON_S("sample_fields") ":" JSON_A(
    2388             :         JSON_S("timestamp_us") ","
    2389             :         JSON_S("last_assigned_id")) ","
    2390             :     JSON_S("location_fields") ":" JSON_A(
    2391             :         JSON_S("object_index") ","
    2392             :         JSON_S("script_id") ","
    2393             :         JSON_S("line") ","
    2394             :         JSON_S("column"))));
    2395             : // clang-format on
    2396             : #undef JSON_S
    2397             : #undef JSON_O
    2398             : #undef JSON_A
    2399          35 :   writer_->AddString(",\"node_count\":");
    2400          70 :   writer_->AddNumber(static_cast<unsigned>(snapshot_->entries().size()));
    2401          35 :   writer_->AddString(",\"edge_count\":");
    2402          70 :   writer_->AddNumber(static_cast<double>(snapshot_->edges().size()));
    2403          35 :   writer_->AddString(",\"trace_function_count\":");
    2404             :   uint32_t count = 0;
    2405          35 :   AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker();
    2406          35 :   if (tracker) {
    2407           0 :     count = static_cast<uint32_t>(tracker->function_info_list().size());
    2408             :   }
    2409          35 :   writer_->AddNumber(count);
    2410          35 : }
    2411             : 
    2412             : 
    2413          20 : static void WriteUChar(OutputStreamWriter* w, unibrow::uchar u) {
    2414             :   static const char hex_chars[] = "0123456789ABCDEF";
    2415             :   w->AddString("\\u");
    2416          20 :   w->AddCharacter(hex_chars[(u >> 12) & 0xF]);
    2417          20 :   w->AddCharacter(hex_chars[(u >> 8) & 0xF]);
    2418          20 :   w->AddCharacter(hex_chars[(u >> 4) & 0xF]);
    2419          20 :   w->AddCharacter(hex_chars[u & 0xF]);
    2420          20 : }
    2421             : 
    2422             : 
    2423           0 : void HeapSnapshotJSONSerializer::SerializeTraceTree() {
    2424          30 :   AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker();
    2425          30 :   if (!tracker) return;
    2426             :   AllocationTraceTree* traces = tracker->trace_tree();
    2427           0 :   SerializeTraceNode(traces->root());
    2428             : }
    2429             : 
    2430             : 
    2431           0 : void HeapSnapshotJSONSerializer::SerializeTraceNode(AllocationTraceNode* node) {
    2432             :   // The buffer needs space for 4 unsigned ints, 4 commas, [ and \0
    2433             :   const int kBufferSize =
    2434             :       4 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
    2435             :       + 4 + 1 + 1;
    2436             :   EmbeddedVector<char, kBufferSize> buffer;
    2437             :   int buffer_pos = 0;
    2438             :   buffer_pos = utoa(node->id(), buffer, buffer_pos);
    2439           0 :   buffer[buffer_pos++] = ',';
    2440             :   buffer_pos = utoa(node->function_info_index(), buffer, buffer_pos);
    2441           0 :   buffer[buffer_pos++] = ',';
    2442             :   buffer_pos = utoa(node->allocation_count(), buffer, buffer_pos);
    2443           0 :   buffer[buffer_pos++] = ',';
    2444             :   buffer_pos = utoa(node->allocation_size(), buffer, buffer_pos);
    2445           0 :   buffer[buffer_pos++] = ',';
    2446           0 :   buffer[buffer_pos++] = '[';
    2447           0 :   buffer[buffer_pos++] = '\0';
    2448           0 :   writer_->AddString(buffer.start());
    2449             : 
    2450             :   int i = 0;
    2451           0 :   for (AllocationTraceNode* child : node->children()) {
    2452           0 :     if (i++ > 0) {
    2453           0 :       writer_->AddCharacter(',');
    2454             :     }
    2455           0 :     SerializeTraceNode(child);
    2456             :   }
    2457           0 :   writer_->AddCharacter(']');
    2458           0 : }
    2459             : 
    2460             : 
    2461             : // 0-based position is converted to 1-based during the serialization.
    2462           0 : static int SerializePosition(int position, const Vector<char>& buffer,
    2463             :                              int buffer_pos) {
    2464           0 :   if (position == -1) {
    2465           0 :     buffer[buffer_pos++] = '0';
    2466             :   } else {
    2467             :     DCHECK_GE(position, 0);
    2468           0 :     buffer_pos = utoa(static_cast<unsigned>(position + 1), buffer, buffer_pos);
    2469             :   }
    2470           0 :   return buffer_pos;
    2471             : }
    2472             : 
    2473             : 
    2474          30 : void HeapSnapshotJSONSerializer::SerializeTraceNodeInfos() {
    2475          30 :   AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker();
    2476          60 :   if (!tracker) return;
    2477             :   // The buffer needs space for 6 unsigned ints, 6 commas, \n and \0
    2478             :   const int kBufferSize =
    2479             :       6 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
    2480             :       + 6 + 1 + 1;
    2481             :   EmbeddedVector<char, kBufferSize> buffer;
    2482             :   int i = 0;
    2483           0 :   for (AllocationTracker::FunctionInfo* info : tracker->function_info_list()) {
    2484             :     int buffer_pos = 0;
    2485           0 :     if (i++ > 0) {
    2486           0 :       buffer[buffer_pos++] = ',';
    2487             :     }
    2488           0 :     buffer_pos = utoa(info->function_id, buffer, buffer_pos);
    2489           0 :     buffer[buffer_pos++] = ',';
    2490           0 :     buffer_pos = utoa(GetStringId(info->name), buffer, buffer_pos);
    2491           0 :     buffer[buffer_pos++] = ',';
    2492           0 :     buffer_pos = utoa(GetStringId(info->script_name), buffer, buffer_pos);
    2493           0 :     buffer[buffer_pos++] = ',';
    2494             :     // The cast is safe because script id is a non-negative Smi.
    2495           0 :     buffer_pos = utoa(static_cast<unsigned>(info->script_id), buffer,
    2496             :         buffer_pos);
    2497           0 :     buffer[buffer_pos++] = ',';
    2498           0 :     buffer_pos = SerializePosition(info->line, buffer, buffer_pos);
    2499           0 :     buffer[buffer_pos++] = ',';
    2500           0 :     buffer_pos = SerializePosition(info->column, buffer, buffer_pos);
    2501           0 :     buffer[buffer_pos++] = '\n';
    2502           0 :     buffer[buffer_pos++] = '\0';
    2503           0 :     writer_->AddString(buffer.start());
    2504             :   }
    2505             : }
    2506             : 
    2507             : 
    2508          30 : void HeapSnapshotJSONSerializer::SerializeSamples() {
    2509             :   const std::vector<HeapObjectsMap::TimeInterval>& samples =
    2510          30 :       snapshot_->profiler()->heap_object_map()->samples();
    2511          60 :   if (samples.empty()) return;
    2512           0 :   base::TimeTicks start_time = samples[0].timestamp;
    2513             :   // The buffer needs space for 2 unsigned ints, 2 commas, \n and \0
    2514             :   const int kBufferSize = MaxDecimalDigitsIn<sizeof(
    2515             :                               base::TimeDelta().InMicroseconds())>::kUnsigned +
    2516             :                           MaxDecimalDigitsIn<sizeof(samples[0].id)>::kUnsigned +
    2517             :                           2 + 1 + 1;
    2518             :   EmbeddedVector<char, kBufferSize> buffer;
    2519             :   int i = 0;
    2520           0 :   for (const HeapObjectsMap::TimeInterval& sample : samples) {
    2521             :     int buffer_pos = 0;
    2522           0 :     if (i++ > 0) {
    2523           0 :       buffer[buffer_pos++] = ',';
    2524             :     }
    2525           0 :     base::TimeDelta time_delta = sample.timestamp - start_time;
    2526           0 :     buffer_pos = utoa(time_delta.InMicroseconds(), buffer, buffer_pos);
    2527           0 :     buffer[buffer_pos++] = ',';
    2528             :     buffer_pos = utoa(sample.last_assigned_id(), buffer, buffer_pos);
    2529           0 :     buffer[buffer_pos++] = '\n';
    2530           0 :     buffer[buffer_pos++] = '\0';
    2531           0 :     writer_->AddString(buffer.start());
    2532             :   }
    2533             : }
    2534             : 
    2535             : 
    2536      200632 : void HeapSnapshotJSONSerializer::SerializeString(const unsigned char* s) {
    2537      200632 :   writer_->AddCharacter('\n');
    2538      200632 :   writer_->AddCharacter('\"');
    2539     8221076 :   for ( ; *s != '\0'; ++s) {
    2540     4010222 :     switch (*s) {
    2541             :       case '\b':
    2542           5 :         writer_->AddString("\\b");
    2543             :         continue;
    2544             :       case '\f':
    2545           0 :         writer_->AddString("\\f");
    2546             :         continue;
    2547             :       case '\n':
    2548        1045 :         writer_->AddString("\\n");
    2549             :         continue;
    2550             :       case '\r':
    2551           5 :         writer_->AddString("\\r");
    2552             :         continue;
    2553             :       case '\t':
    2554           0 :         writer_->AddString("\\t");
    2555             :         continue;
    2556             :       case '\"':
    2557             :       case '\\':
    2558         345 :         writer_->AddCharacter('\\');
    2559         345 :         writer_->AddCharacter(*s);
    2560             :         continue;
    2561             :       default:
    2562     4008822 :         if (*s > 31 && *s < 128) {
    2563     4008802 :           writer_->AddCharacter(*s);
    2564          20 :         } else if (*s <= 31) {
    2565             :           // Special character with no dedicated literal.
    2566           0 :           WriteUChar(writer_, *s);
    2567             :         } else {
    2568             :           // Convert UTF-8 into \u UTF-16 literal.
    2569          20 :           size_t length = 1, cursor = 0;
    2570          90 :           for ( ; length <= 4 && *(s + length) != '\0'; ++length) { }
    2571          20 :           unibrow::uchar c = unibrow::Utf8::CalculateValue(s, length, &cursor);
    2572          20 :           if (c != unibrow::Utf8::kBadChar) {
    2573          20 :             WriteUChar(writer_, c);
    2574             :             DCHECK_NE(cursor, 0);
    2575          20 :             s += cursor - 1;
    2576             :           } else {
    2577           0 :             writer_->AddCharacter('?');
    2578             :           }
    2579             :         }
    2580             :     }
    2581             :   }
    2582      200632 :   writer_->AddCharacter('\"');
    2583      200632 : }
    2584             : 
    2585             : 
    2586          30 : void HeapSnapshotJSONSerializer::SerializeStrings() {
    2587             :   ScopedVector<const unsigned char*> sorted_strings(
    2588          30 :       strings_.occupancy() + 1);
    2589      401294 :   for (base::HashMap::Entry* entry = strings_.Start(); entry != nullptr;
    2590             :        entry = strings_.Next(entry)) {
    2591      200632 :     int index = static_cast<int>(reinterpret_cast<uintptr_t>(entry->value));
    2592      401264 :     sorted_strings[index] = reinterpret_cast<const unsigned char*>(entry->key);
    2593             :   }
    2594          30 :   writer_->AddString("\"<dummy>\"");
    2595      401294 :   for (int i = 1; i < sorted_strings.length(); ++i) {
    2596      200632 :     writer_->AddCharacter(',');
    2597      401264 :     SerializeString(sorted_strings[i]);
    2598      200632 :     if (writer_->aborted()) return;
    2599             :   }
    2600             : }
    2601             : 
    2602         365 : void HeapSnapshotJSONSerializer::SerializeLocation(
    2603             :     const SourceLocation& location) {
    2604             :   // The buffer needs space for 4 unsigned ints, 3 commas, \n and \0
    2605             :   static const int kBufferSize =
    2606             :       MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned * 4 + 3 + 2;
    2607             :   EmbeddedVector<char, kBufferSize> buffer;
    2608             :   int buffer_pos = 0;
    2609         365 :   buffer_pos = utoa(to_node_index(location.entry_index), buffer, buffer_pos);
    2610         730 :   buffer[buffer_pos++] = ',';
    2611         365 :   buffer_pos = utoa(location.scriptId, buffer, buffer_pos);
    2612         730 :   buffer[buffer_pos++] = ',';
    2613         365 :   buffer_pos = utoa(location.line, buffer, buffer_pos);
    2614         730 :   buffer[buffer_pos++] = ',';
    2615         365 :   buffer_pos = utoa(location.col, buffer, buffer_pos);
    2616         730 :   buffer[buffer_pos++] = '\n';
    2617         730 :   buffer[buffer_pos++] = '\0';
    2618         365 :   writer_->AddString(buffer.start());
    2619         365 : }
    2620             : 
    2621          30 : void HeapSnapshotJSONSerializer::SerializeLocations() {
    2622          30 :   const std::vector<SourceLocation>& locations = snapshot_->locations();
    2623         760 :   for (size_t i = 0; i < locations.size(); i++) {
    2624         365 :     if (i > 0) writer_->AddCharacter(',');
    2625         365 :     SerializeLocation(locations[i]);
    2626         365 :     if (writer_->aborted()) return;
    2627             :   }
    2628             : }
    2629             : 
    2630             : }  // namespace internal
    2631      122036 : }  // namespace v8

Generated by: LCOV version 1.10