diff options
Diffstat (limited to 'deps/v8/src/profiler')
-rw-r--r-- | deps/v8/src/profiler/allocation-tracker.cc | 5 | ||||
-rw-r--r-- | deps/v8/src/profiler/allocation-tracker.h | 2 | ||||
-rw-r--r-- | deps/v8/src/profiler/circular-queue-inl.h | 7 | ||||
-rw-r--r-- | deps/v8/src/profiler/cpu-profiler.h | 6 | ||||
-rw-r--r-- | deps/v8/src/profiler/heap-profiler.cc | 14 | ||||
-rw-r--r-- | deps/v8/src/profiler/heap-profiler.h | 4 | ||||
-rw-r--r-- | deps/v8/src/profiler/heap-snapshot-generator-inl.h | 40 | ||||
-rw-r--r-- | deps/v8/src/profiler/heap-snapshot-generator.cc | 1130 | ||||
-rw-r--r-- | deps/v8/src/profiler/heap-snapshot-generator.h | 314 | ||||
-rw-r--r-- | deps/v8/src/profiler/sampling-heap-profiler.cc | 46 | ||||
-rw-r--r-- | deps/v8/src/profiler/sampling-heap-profiler.h | 18 | ||||
-rw-r--r-- | deps/v8/src/profiler/tick-sample.cc | 2 | ||||
-rw-r--r-- | deps/v8/src/profiler/tracing-cpu-profiler.h | 2 | ||||
-rw-r--r-- | deps/v8/src/profiler/unbound-queue.h | 4 |
14 files changed, 617 insertions, 977 deletions
diff --git a/deps/v8/src/profiler/allocation-tracker.cc b/deps/v8/src/profiler/allocation-tracker.cc index e5b3139785..51cb0eb47f 100644 --- a/deps/v8/src/profiler/allocation-tracker.cc +++ b/deps/v8/src/profiler/allocation-tracker.cc @@ -75,11 +75,6 @@ AllocationTraceTree::AllocationTraceTree() root_(this, 0) { } - -AllocationTraceTree::~AllocationTraceTree() { -} - - AllocationTraceNode* AllocationTraceTree::AddPathFromEnd( const Vector<unsigned>& path) { AllocationTraceNode* node = root(); diff --git a/deps/v8/src/profiler/allocation-tracker.h b/deps/v8/src/profiler/allocation-tracker.h index cd9e120db2..bff9a62750 100644 --- a/deps/v8/src/profiler/allocation-tracker.h +++ b/deps/v8/src/profiler/allocation-tracker.h @@ -57,7 +57,7 @@ class AllocationTraceNode { class AllocationTraceTree { public: AllocationTraceTree(); - ~AllocationTraceTree(); + ~AllocationTraceTree() = default; AllocationTraceNode* AddPathFromEnd(const Vector<unsigned>& path); AllocationTraceNode* root() { return &root_; } unsigned next_node_id() { return next_node_id_++; } diff --git a/deps/v8/src/profiler/circular-queue-inl.h b/deps/v8/src/profiler/circular-queue-inl.h index 413b236d37..855e217805 100644 --- a/deps/v8/src/profiler/circular-queue-inl.h +++ b/deps/v8/src/profiler/circular-queue-inl.h @@ -16,11 +16,8 @@ SamplingCircularQueue<T, L>::SamplingCircularQueue() dequeue_pos_(buffer_) { } - -template<typename T, unsigned L> -SamplingCircularQueue<T, L>::~SamplingCircularQueue() { -} - +template <typename T, unsigned L> +SamplingCircularQueue<T, L>::~SamplingCircularQueue() = default; template<typename T, unsigned L> T* SamplingCircularQueue<T, L>::Peek() { diff --git a/deps/v8/src/profiler/cpu-profiler.h b/deps/v8/src/profiler/cpu-profiler.h index 78bb3b4a25..6e2acdfde7 100644 --- a/deps/v8/src/profiler/cpu-profiler.h +++ b/deps/v8/src/profiler/cpu-profiler.h @@ -106,7 +106,7 @@ class TickSampleEventRecord { public: // The parameterless constructor is used when we dequeue data from // the ticks buffer. - TickSampleEventRecord() { } + TickSampleEventRecord() = default; explicit TickSampleEventRecord(unsigned order) : order(order) { } unsigned order; @@ -135,10 +135,10 @@ class ProfilerEventsProcessor : public base::Thread { public: ProfilerEventsProcessor(Isolate* isolate, ProfileGenerator* generator, base::TimeDelta period); - virtual ~ProfilerEventsProcessor(); + ~ProfilerEventsProcessor() override; // Thread control. - virtual void Run(); + void Run() override; void StopSynchronously(); V8_INLINE bool running() { return !!base::Relaxed_Load(&running_); } void Enqueue(const CodeEventsContainer& event); diff --git a/deps/v8/src/profiler/heap-profiler.cc b/deps/v8/src/profiler/heap-profiler.cc index 3a1df29bd4..0978e76cff 100644 --- a/deps/v8/src/profiler/heap-profiler.cc +++ b/deps/v8/src/profiler/heap-profiler.cc @@ -23,14 +23,9 @@ HeapProfiler::~HeapProfiler() = default; void HeapProfiler::DeleteAllSnapshots() { snapshots_.clear(); - MaybeClearStringsStorage(); + names_.reset(new StringsStorage()); } -void HeapProfiler::MaybeClearStringsStorage() { - if (snapshots_.empty() && !sampling_heap_profiler_ && !allocation_tracker_) { - names_.reset(new StringsStorage()); - } -} void HeapProfiler::RemoveSnapshot(HeapSnapshot* snapshot) { snapshots_.erase( @@ -131,7 +126,6 @@ bool HeapProfiler::StartSamplingHeapProfiler( void HeapProfiler::StopSamplingHeapProfiler() { sampling_heap_profiler_.reset(); - MaybeClearStringsStorage(); } @@ -165,7 +159,6 @@ void HeapProfiler::StopHeapObjectsTracking() { ids_->StopHeapObjectsTracking(); if (allocation_tracker_) { allocation_tracker_.reset(); - MaybeClearStringsStorage(); heap()->RemoveHeapObjectAllocationTracker(this); } } @@ -236,10 +229,7 @@ void HeapProfiler::QueryObjects(Handle<Context> context, PersistentValueVector<v8::Object>* objects) { // We should return accurate information about live objects, so we need to // collect all garbage first. - heap()->CollectAllAvailableGarbage( - GarbageCollectionReason::kLowMemoryNotification); - heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask, - GarbageCollectionReason::kHeapProfiler); + heap()->CollectAllAvailableGarbage(GarbageCollectionReason::kHeapProfiler); HeapIterator heap_iterator(heap()); HeapObject* heap_obj; while ((heap_obj = heap_iterator.next()) != nullptr) { diff --git a/deps/v8/src/profiler/heap-profiler.h b/deps/v8/src/profiler/heap-profiler.h index 099c0e24fa..acbdc6aa7a 100644 --- a/deps/v8/src/profiler/heap-profiler.h +++ b/deps/v8/src/profiler/heap-profiler.h @@ -27,7 +27,7 @@ class StringsStorage; class HeapProfiler : public HeapObjectAllocationTracker { public: explicit HeapProfiler(Heap* heap); - ~HeapProfiler(); + ~HeapProfiler() override; HeapSnapshot* TakeSnapshot( v8::ActivityControl* control, @@ -92,8 +92,6 @@ class HeapProfiler : public HeapObjectAllocationTracker { v8::PersistentValueVector<v8::Object>* objects); private: - void MaybeClearStringsStorage(); - Heap* heap() const; // Mapping from HeapObject addresses to objects' uids. diff --git a/deps/v8/src/profiler/heap-snapshot-generator-inl.h b/deps/v8/src/profiler/heap-snapshot-generator-inl.h index edf6559706..6ddb6d4658 100644 --- a/deps/v8/src/profiler/heap-snapshot-generator-inl.h +++ b/deps/v8/src/profiler/heap-snapshot-generator-inl.h @@ -13,51 +13,41 @@ namespace v8 { namespace internal { - HeapEntry* HeapGraphEdge::from() const { return &snapshot()->entries()[from_index()]; } - -Isolate* HeapGraphEdge::isolate() const { - return snapshot()->profiler()->isolate(); -} - +Isolate* HeapGraphEdge::isolate() const { return to_entry_->isolate(); } HeapSnapshot* HeapGraphEdge::snapshot() const { return to_entry_->snapshot(); } - -int HeapEntry::index() const { - return static_cast<int>(this - &snapshot_->entries().front()); -} - - int HeapEntry::set_children_index(int index) { - children_index_ = index; + // Note: children_count_ and children_end_index_ are parts of a union. int next_index = index + children_count_; - children_count_ = 0; + children_end_index_ = index; return next_index; } void HeapEntry::add_child(HeapGraphEdge* edge) { - *(children_begin() + children_count_++) = edge; + snapshot_->children()[children_end_index_++] = edge; } -HeapGraphEdge* HeapEntry::child(int i) { return *(children_begin() + i); } +HeapGraphEdge* HeapEntry::child(int i) { return children_begin()[i]; } + +std::vector<HeapGraphEdge*>::iterator HeapEntry::children_begin() const { + return index_ == 0 ? snapshot_->children().begin() + : snapshot_->entries()[index_ - 1].children_end(); +} -std::deque<HeapGraphEdge*>::iterator HeapEntry::children_begin() { - DCHECK_GE(children_index_, 0); - SLOW_DCHECK( - children_index_ < static_cast<int>(snapshot_->children().size()) || - (children_index_ == static_cast<int>(snapshot_->children().size()) && - children_count_ == 0)); - return snapshot_->children().begin() + children_index_; +std::vector<HeapGraphEdge*>::iterator HeapEntry::children_end() const { + DCHECK_GE(children_end_index_, 0); + return snapshot_->children().begin() + children_end_index_; } -std::deque<HeapGraphEdge*>::iterator HeapEntry::children_end() { - return children_begin() + children_count_; +int HeapEntry::children_count() const { + return static_cast<int>(children_end() - children_begin()); } Isolate* HeapEntry::isolate() const { return snapshot_->profiler()->isolate(); } diff --git a/deps/v8/src/profiler/heap-snapshot-generator.cc b/deps/v8/src/profiler/heap-snapshot-generator.cc index 5d98a98b8e..57f620f4ec 100644 --- a/deps/v8/src/profiler/heap-snapshot-generator.cc +++ b/deps/v8/src/profiler/heap-snapshot-generator.cc @@ -33,10 +33,11 @@ namespace v8 { namespace internal { - -HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to) - : bit_field_(TypeField::encode(type) | FromIndexField::encode(from)), - to_index_(to), +HeapGraphEdge::HeapGraphEdge(Type type, const char* name, HeapEntry* from, + HeapEntry* to) + : bit_field_(TypeField::encode(type) | + FromIndexField::encode(from->index())), + to_entry_(to), name_(name) { DCHECK(type == kContextVariable || type == kProperty @@ -45,55 +46,53 @@ HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to) || type == kWeak); } - -HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to) - : bit_field_(TypeField::encode(type) | FromIndexField::encode(from)), - to_index_(to), +HeapGraphEdge::HeapGraphEdge(Type type, int index, HeapEntry* from, + HeapEntry* to) + : bit_field_(TypeField::encode(type) | + FromIndexField::encode(from->index())), + to_entry_(to), index_(index) { DCHECK(type == kElement || type == kHidden); } - -void HeapGraphEdge::ReplaceToIndexWithEntry(HeapSnapshot* snapshot) { - to_entry_ = &snapshot->entries()[to_index_]; -} - - -const int HeapEntry::kNoEntry = -1; - -HeapEntry::HeapEntry(HeapSnapshot* snapshot, - Type type, - const char* name, - SnapshotObjectId id, - size_t self_size, +HeapEntry::HeapEntry(HeapSnapshot* snapshot, int index, Type type, + const char* name, SnapshotObjectId id, size_t self_size, unsigned trace_node_id) : type_(type), + index_(index), children_count_(0), - children_index_(-1), self_size_(self_size), snapshot_(snapshot), name_(name), id_(id), - trace_node_id_(trace_node_id) { } - + trace_node_id_(trace_node_id) { + DCHECK_GE(index, 0); +} void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, const char* name, HeapEntry* entry) { - HeapGraphEdge edge(type, name, this->index(), entry->index()); - snapshot_->edges().push_back(edge); ++children_count_; + snapshot_->edges().emplace_back(type, name, this, entry); } - void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, int index, HeapEntry* entry) { - HeapGraphEdge edge(type, index, this->index(), entry->index()); - snapshot_->edges().push_back(edge); ++children_count_; + snapshot_->edges().emplace_back(type, index, this, entry); } +void HeapEntry::SetNamedAutoIndexReference(HeapGraphEdge::Type type, + const char* description, + HeapEntry* child, + StringsStorage* names) { + int index = children_count_ + 1; + const char* name = description + ? names->GetFormatted("%d / %s", index, description) + : names->GetName(index); + SetNamedReference(type, name, child); +} void HeapEntry::Print( const char* prefix, const char* edge_name, int max_depth, int indent) { @@ -154,7 +153,6 @@ void HeapEntry::Print( } } - const char* HeapEntry::TypeAsString() { switch (type()) { case kHidden: return "/hidden/"; @@ -176,34 +174,24 @@ const char* HeapEntry::TypeAsString() { } } - -HeapSnapshot::HeapSnapshot(HeapProfiler* profiler) - : profiler_(profiler), - root_index_(HeapEntry::kNoEntry), - gc_roots_index_(HeapEntry::kNoEntry), - max_snapshot_js_object_id_(0) { +HeapSnapshot::HeapSnapshot(HeapProfiler* profiler) : profiler_(profiler) { // It is very important to keep objects that form a heap snapshot // as small as possible. Check assumptions about data structure sizes. - STATIC_ASSERT(((kPointerSize == 4) && (sizeof(HeapGraphEdge) == 12)) || - ((kPointerSize == 8) && (sizeof(HeapGraphEdge) == 24))); - STATIC_ASSERT(((kPointerSize == 4) && (sizeof(HeapEntry) == 28)) || - ((kPointerSize == 8) && (sizeof(HeapEntry) == 40))); - for (int i = 0; i < static_cast<int>(Root::kNumberOfRoots); ++i) { - gc_subroot_indexes_[i] = HeapEntry::kNoEntry; - } + STATIC_ASSERT((kPointerSize == 4 && sizeof(HeapGraphEdge) == 12) || + (kPointerSize == 8 && sizeof(HeapGraphEdge) == 24)); + STATIC_ASSERT((kPointerSize == 4 && sizeof(HeapEntry) == 28) || + (kPointerSize == 8 && sizeof(HeapEntry) == 40)); + memset(&gc_subroot_entries_, 0, sizeof(gc_subroot_entries_)); } - void HeapSnapshot::Delete() { profiler_->RemoveSnapshot(this); } - void HeapSnapshot::RememberLastJSObjectId() { max_snapshot_js_object_id_ = profiler_->heap_object_map()->last_assigned_id(); } - void HeapSnapshot::AddSyntheticRootEntries() { AddRootEntry(); AddGcRootsEntry(); @@ -215,42 +203,30 @@ void HeapSnapshot::AddSyntheticRootEntries() { DCHECK_EQ(HeapObjectsMap::kFirstAvailableObjectId, id); } - -HeapEntry* HeapSnapshot::AddRootEntry() { - DCHECK_EQ(root_index_, HeapEntry::kNoEntry); +void HeapSnapshot::AddRootEntry() { + DCHECK_NULL(root_entry_); DCHECK(entries_.empty()); // Root entry must be the first one. - HeapEntry* entry = AddEntry(HeapEntry::kSynthetic, - "", - HeapObjectsMap::kInternalRootObjectId, - 0, - 0); - root_index_ = entry->index(); - DCHECK_EQ(root_index_, 0); - return entry; -} - - -HeapEntry* HeapSnapshot::AddGcRootsEntry() { - DCHECK_EQ(gc_roots_index_, HeapEntry::kNoEntry); - HeapEntry* entry = AddEntry(HeapEntry::kSynthetic, - "(GC roots)", - HeapObjectsMap::kGcRootsObjectId, - 0, - 0); - gc_roots_index_ = entry->index(); - return entry; -} - -HeapEntry* HeapSnapshot::AddGcSubrootEntry(Root root, SnapshotObjectId id) { - DCHECK_EQ(gc_subroot_indexes_[static_cast<int>(root)], HeapEntry::kNoEntry); - HeapEntry* entry = + root_entry_ = AddEntry(HeapEntry::kSynthetic, "", + HeapObjectsMap::kInternalRootObjectId, 0, 0); + DCHECK_EQ(1u, entries_.size()); + DCHECK_EQ(root_entry_, &entries_.front()); +} + +void HeapSnapshot::AddGcRootsEntry() { + DCHECK_NULL(gc_roots_entry_); + gc_roots_entry_ = AddEntry(HeapEntry::kSynthetic, "(GC roots)", + HeapObjectsMap::kGcRootsObjectId, 0, 0); +} + +void HeapSnapshot::AddGcSubrootEntry(Root root, SnapshotObjectId id) { + DCHECK_NULL(gc_subroot_entries_[static_cast<int>(root)]); + gc_subroot_entries_[static_cast<int>(root)] = AddEntry(HeapEntry::kSynthetic, RootVisitor::RootName(root), id, 0, 0); - gc_subroot_indexes_[static_cast<int>(root)] = entry->index(); - return entry; } -void HeapSnapshot::AddLocation(int entry, int scriptId, int line, int col) { - locations_.emplace_back(entry, scriptId, line, col); +void HeapSnapshot::AddLocation(HeapEntry* entry, int scriptId, int line, + int col) { + locations_.emplace_back(entry->index(), scriptId, line, col); } HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, @@ -258,52 +234,35 @@ HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, SnapshotObjectId id, size_t size, unsigned trace_node_id) { - DCHECK(sorted_entries_.empty()); - entries_.emplace_back(this, type, name, id, size, trace_node_id); + DCHECK(!is_complete()); + entries_.emplace_back(this, static_cast<int>(entries_.size()), type, name, id, + size, trace_node_id); return &entries_.back(); } - void HeapSnapshot::FillChildren() { DCHECK(children().empty()); - children().resize(edges().size()); int children_index = 0; for (HeapEntry& entry : entries()) { children_index = entry.set_children_index(children_index); } DCHECK_EQ(edges().size(), static_cast<size_t>(children_index)); + children().resize(edges().size()); for (HeapGraphEdge& edge : edges()) { - edge.ReplaceToIndexWithEntry(this); edge.from()->add_child(&edge); } } HeapEntry* HeapSnapshot::GetEntryById(SnapshotObjectId id) { - std::vector<HeapEntry*>* entries_by_id = GetSortedEntriesList(); - - auto it = std::lower_bound( - entries_by_id->begin(), entries_by_id->end(), id, - [](HeapEntry* first, SnapshotObjectId val) { return first->id() < val; }); - - if (it == entries_by_id->end() || (*it)->id() != id) return nullptr; - return *it; -} - -struct SortByIds { - bool operator()(const HeapEntry* entry1_ptr, const HeapEntry* entry2_ptr) { - return entry1_ptr->id() < entry2_ptr->id(); - } -}; - -std::vector<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { - if (sorted_entries_.empty()) { - sorted_entries_.reserve(entries_.size()); + if (entries_by_id_cache_.empty()) { + CHECK(is_complete()); + entries_by_id_cache_.reserve(entries_.size()); for (HeapEntry& entry : entries_) { - sorted_entries_.push_back(&entry); + entries_by_id_cache_.emplace(entry.id(), &entry); } - std::sort(sorted_entries_.begin(), sorted_entries_.end(), SortByIds()); } - return &sorted_entries_; + auto it = entries_by_id_cache_.find(id); + return it != entries_by_id_cache_.end() ? it->second : nullptr; } void HeapSnapshot::Print(int max_depth) { @@ -427,8 +386,8 @@ void HeapObjectsMap::UpdateHeapObjectsMap() { PrintF("Begin HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n", entries_map_.occupancy()); } - heap_->CollectAllGarbage(Heap::kMakeHeapIterableMask, - GarbageCollectionReason::kHeapProfiler); + heap_->PreciseCollectAllGarbage(Heap::kNoGCFlags, + GarbageCollectionReason::kHeapProfiler); HeapIterator iterator(heap_); for (HeapObject* obj = iterator.next(); obj != nullptr; obj = iterator.next()) { @@ -540,61 +499,6 @@ SnapshotObjectId HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) { return id << 1; } -HeapEntriesMap::HeapEntriesMap() : entries_() {} - -int HeapEntriesMap::Map(HeapThing thing) { - base::HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing)); - if (cache_entry == nullptr) return HeapEntry::kNoEntry; - return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value)); -} - - -void HeapEntriesMap::Pair(HeapThing thing, int entry) { - base::HashMap::Entry* cache_entry = - entries_.LookupOrInsert(thing, Hash(thing)); - DCHECK_NULL(cache_entry->value); - cache_entry->value = reinterpret_cast<void*>(static_cast<intptr_t>(entry)); -} - -HeapObjectsSet::HeapObjectsSet() : entries_() {} - -void HeapObjectsSet::Clear() { - entries_.Clear(); -} - - -bool HeapObjectsSet::Contains(Object* obj) { - if (!obj->IsHeapObject()) return false; - HeapObject* object = HeapObject::cast(obj); - return entries_.Lookup(object, HeapEntriesMap::Hash(object)) != nullptr; -} - - -void HeapObjectsSet::Insert(Object* obj) { - if (!obj->IsHeapObject()) return; - HeapObject* object = HeapObject::cast(obj); - entries_.LookupOrInsert(object, HeapEntriesMap::Hash(object)); -} - - -const char* HeapObjectsSet::GetTag(Object* obj) { - HeapObject* object = HeapObject::cast(obj); - base::HashMap::Entry* cache_entry = - entries_.Lookup(object, HeapEntriesMap::Hash(object)); - return cache_entry != nullptr - ? reinterpret_cast<const char*>(cache_entry->value) - : nullptr; -} - - -V8_NOINLINE void HeapObjectsSet::SetTag(Object* obj, const char* tag) { - if (!obj->IsHeapObject()) return; - HeapObject* object = HeapObject::cast(obj); - base::HashMap::Entry* cache_entry = - entries_.LookupOrInsert(object, HeapEntriesMap::Hash(object)); - cache_entry->value = const_cast<char*>(tag); -} - V8HeapExplorer::V8HeapExplorer(HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress, v8::HeapProfiler::ObjectNameResolver* resolver) @@ -603,18 +507,14 @@ V8HeapExplorer::V8HeapExplorer(HeapSnapshot* snapshot, names_(snapshot_->profiler()->names()), heap_object_map_(snapshot_->profiler()->heap_object_map()), progress_(progress), - filler_(nullptr), + generator_(nullptr), global_object_name_resolver_(resolver) {} -V8HeapExplorer::~V8HeapExplorer() { -} - - HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) { return AddEntry(reinterpret_cast<HeapObject*>(ptr)); } -void V8HeapExplorer::ExtractLocation(int entry, HeapObject* object) { +void V8HeapExplorer::ExtractLocation(HeapEntry* entry, HeapObject* object) { if (object->IsJSFunction()) { JSFunction* func = JSFunction::cast(object); ExtractLocationForJSFunction(entry, func); @@ -632,7 +532,8 @@ void V8HeapExplorer::ExtractLocation(int entry, HeapObject* object) { } } -void V8HeapExplorer::ExtractLocationForJSFunction(int entry, JSFunction* func) { +void V8HeapExplorer::ExtractLocationForJSFunction(HeapEntry* entry, + JSFunction* func) { if (!func->shared()->script()->IsScript()) return; Script* script = Script::cast(func->shared()->script()); int scriptId = script->id(); @@ -659,25 +560,22 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) { const char* name = names_->GetName( GetConstructorName(JSObject::cast(object))); if (object->IsJSGlobalObject()) { - const char* tag = objects_tags_.GetTag(object); - if (tag != nullptr) { - name = names_->GetFormatted("%s / %s", name, tag); + auto it = objects_tags_.find(JSGlobalObject::cast(object)); + if (it != objects_tags_.end()) { + name = names_->GetFormatted("%s / %s", name, it->second); } } return AddEntry(object, HeapEntry::kObject, name); } else if (object->IsString()) { String* string = String::cast(object); - if (string->IsConsString()) - return AddEntry(object, - HeapEntry::kConsString, - "(concatenated string)"); - if (string->IsSlicedString()) - return AddEntry(object, - HeapEntry::kSlicedString, - "(sliced string)"); - return AddEntry(object, - HeapEntry::kString, - names_->GetName(String::cast(object))); + if (string->IsConsString()) { + return AddEntry(object, HeapEntry::kConsString, "(concatenated string)"); + } else if (string->IsSlicedString()) { + return AddEntry(object, HeapEntry::kSlicedString, "(sliced string)"); + } else { + return AddEntry(object, HeapEntry::kString, + names_->GetName(String::cast(object))); + } } else if (object->IsSymbol()) { if (Symbol::cast(object)->is_private()) return AddEntry(object, HeapEntry::kHidden, "private symbol"); @@ -689,16 +587,12 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) { return AddEntry(object, HeapEntry::kCode, ""); } else if (object->IsSharedFunctionInfo()) { String* name = SharedFunctionInfo::cast(object)->Name(); - return AddEntry(object, - HeapEntry::kCode, - names_->GetName(name)); + return AddEntry(object, HeapEntry::kCode, names_->GetName(name)); } else if (object->IsScript()) { Object* name = Script::cast(object)->name(); - return AddEntry(object, - HeapEntry::kCode, - name->IsString() - ? names_->GetName(String::cast(name)) - : ""); + return AddEntry( + object, HeapEntry::kCode, + name->IsString() ? names_->GetName(String::cast(name)) : ""); } else if (object->IsNativeContext()) { return AddEntry(object, HeapEntry::kHidden, "system / NativeContext"); } else if (object->IsContext()) { @@ -712,14 +606,12 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) { return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object)); } - HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, HeapEntry::Type type, const char* name) { return AddEntry(object->address(), type, name, object->Size()); } - HeapEntry* V8HeapExplorer::AddEntry(Address address, HeapEntry::Type type, const char* name, @@ -735,66 +627,6 @@ HeapEntry* V8HeapExplorer::AddEntry(Address address, return snapshot_->AddEntry(type, name, object_id, size, trace_node_id); } - -class SnapshotFiller { - public: - explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries) - : snapshot_(snapshot), - names_(snapshot->profiler()->names()), - entries_(entries) { } - HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { - HeapEntry* entry = allocator->AllocateEntry(ptr); - entries_->Pair(ptr, entry->index()); - return entry; - } - HeapEntry* FindEntry(HeapThing ptr) { - int index = entries_->Map(ptr); - return index != HeapEntry::kNoEntry ? &snapshot_->entries()[index] - : nullptr; - } - HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { - HeapEntry* entry = FindEntry(ptr); - return entry != nullptr ? entry : AddEntry(ptr, allocator); - } - void SetIndexedReference(HeapGraphEdge::Type type, - int parent, - int index, - HeapEntry* child_entry) { - HeapEntry* parent_entry = &snapshot_->entries()[parent]; - parent_entry->SetIndexedReference(type, index, child_entry); - } - void SetIndexedAutoIndexReference(HeapGraphEdge::Type type, - int parent, - HeapEntry* child_entry) { - HeapEntry* parent_entry = &snapshot_->entries()[parent]; - int index = parent_entry->children_count() + 1; - parent_entry->SetIndexedReference(type, index, child_entry); - } - void SetNamedReference(HeapGraphEdge::Type type, - int parent, - const char* reference_name, - HeapEntry* child_entry) { - HeapEntry* parent_entry = &snapshot_->entries()[parent]; - parent_entry->SetNamedReference(type, reference_name, child_entry); - } - void SetNamedAutoIndexReference(HeapGraphEdge::Type type, int parent, - const char* description, - HeapEntry* child_entry) { - HeapEntry* parent_entry = &snapshot_->entries()[parent]; - int index = parent_entry->children_count() + 1; - const char* name = description - ? names_->GetFormatted("%d / %s", index, description) - : names_->GetName(index); - parent_entry->SetNamedReference(type, name, child_entry); - } - - private: - HeapSnapshot* snapshot_; - StringsStorage* names_; - HeapEntriesMap* entries_; -}; - - const char* V8HeapExplorer::GetSystemEntryName(HeapObject* object) { switch (object->map()->instance_type()) { case MAP_TYPE: @@ -811,9 +643,10 @@ const char* V8HeapExplorer::GetSystemEntryName(HeapObject* object) { case ODDBALL_TYPE: return "system / Oddball"; case ALLOCATION_SITE_TYPE: return "system / AllocationSite"; -#define MAKE_STRUCT_CASE(NAME, Name, name) \ - case NAME##_TYPE: return "system / "#Name; - STRUCT_LIST(MAKE_STRUCT_CASE) +#define MAKE_STRUCT_CASE(TYPE, Name, name) \ + case TYPE: \ + return "system / " #Name; + STRUCT_LIST(MAKE_STRUCT_CASE) #undef MAKE_STRUCT_CASE default: return "system"; } @@ -829,7 +662,7 @@ int V8HeapExplorer::EstimateObjectsCount() { class IndexedReferencesExtractor : public ObjectVisitor { public: IndexedReferencesExtractor(V8HeapExplorer* generator, HeapObject* parent_obj, - int parent) + HeapEntry* parent) : generator_(generator), parent_obj_(parent_obj), parent_start_(HeapObject::RawField(parent_obj_, 0)), @@ -855,8 +688,8 @@ class IndexedReferencesExtractor : public ObjectVisitor { continue; } HeapObject* heap_object; - if ((*p)->ToWeakHeapObject(&heap_object) || - (*p)->ToStrongHeapObject(&heap_object)) { + if ((*p)->GetHeapObjectIfWeak(&heap_object) || + (*p)->GetHeapObjectIfStrong(&heap_object)) { generator_->SetHiddenReference(parent_obj_, parent_, next_index, heap_object, index * kPointerSize); } @@ -868,10 +701,10 @@ class IndexedReferencesExtractor : public ObjectVisitor { HeapObject* parent_obj_; Object** parent_start_; Object** parent_end_; - int parent_; + HeapEntry* parent_; }; -void V8HeapExplorer::ExtractReferences(int entry, HeapObject* obj) { +void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject* obj) { if (obj->IsJSGlobalProxy()) { ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj)); } else if (obj->IsJSArrayBuffer()) { @@ -935,38 +768,35 @@ void V8HeapExplorer::ExtractReferences(int entry, HeapObject* obj) { } } - -void V8HeapExplorer::ExtractJSGlobalProxyReferences( - int entry, JSGlobalProxy* proxy) { - SetInternalReference(proxy, entry, - "native_context", proxy->native_context(), +void V8HeapExplorer::ExtractJSGlobalProxyReferences(HeapEntry* entry, + JSGlobalProxy* proxy) { + SetInternalReference(entry, "native_context", proxy->native_context(), JSGlobalProxy::kNativeContextOffset); } - -void V8HeapExplorer::ExtractJSObjectReferences( - int entry, JSObject* js_obj) { +void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry, + JSObject* js_obj) { HeapObject* obj = js_obj; ExtractPropertyReferences(js_obj, entry); ExtractElementReferences(js_obj, entry); ExtractInternalReferences(js_obj, entry); PrototypeIterator iter(heap_->isolate(), js_obj); ReadOnlyRoots roots(heap_); - SetPropertyReference(obj, entry, roots.proto_string(), iter.GetCurrent()); + SetPropertyReference(entry, roots.proto_string(), iter.GetCurrent()); if (obj->IsJSBoundFunction()) { JSBoundFunction* js_fun = JSBoundFunction::cast(obj); TagObject(js_fun->bound_arguments(), "(bound arguments)"); - SetInternalReference(js_fun, entry, "bindings", js_fun->bound_arguments(), + SetInternalReference(entry, "bindings", js_fun->bound_arguments(), JSBoundFunction::kBoundArgumentsOffset); - SetInternalReference(js_obj, entry, "bound_this", js_fun->bound_this(), + SetInternalReference(entry, "bound_this", js_fun->bound_this(), JSBoundFunction::kBoundThisOffset); - SetInternalReference(js_obj, entry, "bound_function", + SetInternalReference(entry, "bound_function", js_fun->bound_target_function(), JSBoundFunction::kBoundTargetFunctionOffset); FixedArray* bindings = js_fun->bound_arguments(); for (int i = 0; i < bindings->length(); i++) { const char* reference_name = names_->GetFormatted("bound_argument_%d", i); - SetNativeBindReference(js_obj, entry, reference_name, bindings->get(i)); + SetNativeBindReference(entry, reference_name, bindings->get(i)); } } else if (obj->IsJSFunction()) { JSFunction* js_fun = JSFunction::cast(js_obj); @@ -974,124 +804,123 @@ void V8HeapExplorer::ExtractJSObjectReferences( Object* proto_or_map = js_fun->prototype_or_initial_map(); if (!proto_or_map->IsTheHole(heap_->isolate())) { if (!proto_or_map->IsMap()) { - SetPropertyReference(obj, entry, roots.prototype_string(), - proto_or_map, nullptr, + SetPropertyReference(entry, roots.prototype_string(), proto_or_map, + nullptr, JSFunction::kPrototypeOrInitialMapOffset); } else { - SetPropertyReference(obj, entry, roots.prototype_string(), + SetPropertyReference(entry, roots.prototype_string(), js_fun->prototype()); - SetInternalReference(obj, entry, "initial_map", proto_or_map, + SetInternalReference(entry, "initial_map", proto_or_map, JSFunction::kPrototypeOrInitialMapOffset); } } } SharedFunctionInfo* shared_info = js_fun->shared(); TagObject(js_fun->feedback_cell(), "(function feedback cell)"); - SetInternalReference(js_fun, entry, "feedback_cell", - js_fun->feedback_cell(), + SetInternalReference(entry, "feedback_cell", js_fun->feedback_cell(), JSFunction::kFeedbackCellOffset); TagObject(shared_info, "(shared function info)"); - SetInternalReference(js_fun, entry, - "shared", shared_info, + SetInternalReference(entry, "shared", shared_info, JSFunction::kSharedFunctionInfoOffset); TagObject(js_fun->context(), "(context)"); - SetInternalReference(js_fun, entry, - "context", js_fun->context(), + SetInternalReference(entry, "context", js_fun->context(), JSFunction::kContextOffset); TagCodeObject(js_fun->code()); - SetInternalReference(js_fun, entry, "code", js_fun->code(), + SetInternalReference(entry, "code", js_fun->code(), JSFunction::kCodeOffset); } else if (obj->IsJSGlobalObject()) { JSGlobalObject* global_obj = JSGlobalObject::cast(obj); - SetInternalReference(global_obj, entry, "native_context", - global_obj->native_context(), + SetInternalReference(entry, "native_context", global_obj->native_context(), JSGlobalObject::kNativeContextOffset); - SetInternalReference(global_obj, entry, "global_proxy", - global_obj->global_proxy(), + SetInternalReference(entry, "global_proxy", global_obj->global_proxy(), JSGlobalObject::kGlobalProxyOffset); STATIC_ASSERT(JSGlobalObject::kSize - JSObject::kHeaderSize == 2 * kPointerSize); } else if (obj->IsJSArrayBufferView()) { JSArrayBufferView* view = JSArrayBufferView::cast(obj); - SetInternalReference(view, entry, "buffer", view->buffer(), + SetInternalReference(entry, "buffer", view->buffer(), JSArrayBufferView::kBufferOffset); } TagObject(js_obj->raw_properties_or_hash(), "(object properties)"); - SetInternalReference(obj, entry, "properties", - js_obj->raw_properties_or_hash(), + SetInternalReference(entry, "properties", js_obj->raw_properties_or_hash(), JSObject::kPropertiesOrHashOffset); TagObject(js_obj->elements(), "(object elements)"); - SetInternalReference(obj, entry, - "elements", js_obj->elements(), + SetInternalReference(entry, "elements", js_obj->elements(), JSObject::kElementsOffset); } - -void V8HeapExplorer::ExtractStringReferences(int entry, String* string) { +void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, String* string) { if (string->IsConsString()) { ConsString* cs = ConsString::cast(string); - SetInternalReference(cs, entry, "first", cs->first(), - ConsString::kFirstOffset); - SetInternalReference(cs, entry, "second", cs->second(), + SetInternalReference(entry, "first", cs->first(), ConsString::kFirstOffset); + SetInternalReference(entry, "second", cs->second(), ConsString::kSecondOffset); } else if (string->IsSlicedString()) { SlicedString* ss = SlicedString::cast(string); - SetInternalReference(ss, entry, "parent", ss->parent(), + SetInternalReference(entry, "parent", ss->parent(), SlicedString::kParentOffset); } else if (string->IsThinString()) { ThinString* ts = ThinString::cast(string); - SetInternalReference(ts, entry, "actual", ts->actual(), + SetInternalReference(entry, "actual", ts->actual(), ThinString::kActualOffset); } } - -void V8HeapExplorer::ExtractSymbolReferences(int entry, Symbol* symbol) { - SetInternalReference(symbol, entry, - "name", symbol->name(), - Symbol::kNameOffset); +void V8HeapExplorer::ExtractSymbolReferences(HeapEntry* entry, Symbol* symbol) { + SetInternalReference(entry, "name", symbol->name(), Symbol::kNameOffset); } - -void V8HeapExplorer::ExtractJSCollectionReferences(int entry, +void V8HeapExplorer::ExtractJSCollectionReferences(HeapEntry* entry, JSCollection* collection) { - SetInternalReference(collection, entry, "table", collection->table(), + SetInternalReference(entry, "table", collection->table(), JSCollection::kTableOffset); } -void V8HeapExplorer::ExtractJSWeakCollectionReferences(int entry, +void V8HeapExplorer::ExtractJSWeakCollectionReferences(HeapEntry* entry, JSWeakCollection* obj) { - SetInternalReference(obj, entry, "table", obj->table(), + SetInternalReference(entry, "table", obj->table(), JSWeakCollection::kTableOffset); } void V8HeapExplorer::ExtractEphemeronHashTableReferences( - int entry, EphemeronHashTable* table) { + HeapEntry* entry, EphemeronHashTable* table) { for (int i = 0, capacity = table->Capacity(); i < capacity; ++i) { int key_index = EphemeronHashTable::EntryToIndex(i) + EphemeronHashTable::kEntryKeyIndex; int value_index = EphemeronHashTable::EntryToValueIndex(i); Object* key = table->get(key_index); Object* value = table->get(value_index); - SetWeakReference(table, entry, key_index, key, + SetWeakReference(entry, key_index, key, table->OffsetOfElementAt(key_index)); - SetInternalReference(table, entry, value_index, value, - table->OffsetOfElementAt(value_index)); + SetWeakReference(entry, value_index, value, + table->OffsetOfElementAt(value_index)); HeapEntry* key_entry = GetEntry(key); - int key_entry_index = key_entry->index(); HeapEntry* value_entry = GetEntry(value); if (key_entry && value_entry) { const char* edge_name = names_->GetFormatted("key %s in WeakMap", key_entry->name()); - filler_->SetNamedAutoIndexReference( - HeapGraphEdge::kInternal, key_entry_index, edge_name, value_entry); + key_entry->SetNamedAutoIndexReference(HeapGraphEdge::kInternal, edge_name, + value_entry, names_); } } } -void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) { +// These static arrays are used to prevent excessive code-size in +// ExtractContextReferences below, which would happen if we called +// SetInternalReference for every native context field in a macro. +static const struct { + int index; + const char* name; +} native_context_names[] = { +#define CONTEXT_FIELD_INDEX_NAME(index, _, name) {Context::index, #name}, + NATIVE_CONTEXT_FIELDS(CONTEXT_FIELD_INDEX_NAME) +#undef CONTEXT_FIELD_INDEX +}; + +void V8HeapExplorer::ExtractContextReferences(HeapEntry* entry, + Context* context) { if (!context->IsNativeContext() && context->is_declaration_context()) { ScopeInfo* scope_info = context->scope_info(); // Add context allocated locals. @@ -1099,39 +928,49 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) { for (int i = 0; i < context_locals; ++i) { String* local_name = scope_info->ContextLocalName(i); int idx = Context::MIN_CONTEXT_SLOTS + i; - SetContextReference(context, entry, local_name, context->get(idx), + SetContextReference(entry, local_name, context->get(idx), Context::OffsetOfElementAt(idx)); } if (scope_info->HasFunctionName()) { String* name = String::cast(scope_info->FunctionName()); int idx = scope_info->FunctionContextSlotIndex(name); if (idx >= 0) { - SetContextReference(context, entry, name, context->get(idx), + SetContextReference(entry, name, context->get(idx), Context::OffsetOfElementAt(idx)); } } } -#define EXTRACT_CONTEXT_FIELD(index, type, name) \ - if (Context::index < Context::FIRST_WEAK_SLOT || \ - Context::index == Context::MAP_CACHE_INDEX) { \ - SetInternalReference(context, entry, #name, context->get(Context::index), \ - FixedArray::OffsetOfElementAt(Context::index)); \ - } else { \ - SetWeakReference(context, entry, #name, context->get(Context::index), \ - FixedArray::OffsetOfElementAt(Context::index)); \ - } - EXTRACT_CONTEXT_FIELD(SCOPE_INFO_INDEX, ScopeInfo, scope_info); - EXTRACT_CONTEXT_FIELD(PREVIOUS_INDEX, Context, previous); - EXTRACT_CONTEXT_FIELD(EXTENSION_INDEX, HeapObject, extension); - EXTRACT_CONTEXT_FIELD(NATIVE_CONTEXT_INDEX, Context, native_context); + SetInternalReference( + entry, "scope_info", context->get(Context::SCOPE_INFO_INDEX), + FixedArray::OffsetOfElementAt(Context::SCOPE_INFO_INDEX)); + SetInternalReference(entry, "previous", context->get(Context::PREVIOUS_INDEX), + FixedArray::OffsetOfElementAt(Context::PREVIOUS_INDEX)); + SetInternalReference(entry, "extension", + context->get(Context::EXTENSION_INDEX), + FixedArray::OffsetOfElementAt(Context::EXTENSION_INDEX)); + SetInternalReference( + entry, "native_context", context->get(Context::NATIVE_CONTEXT_INDEX), + FixedArray::OffsetOfElementAt(Context::NATIVE_CONTEXT_INDEX)); + if (context->IsNativeContext()) { TagObject(context->normalized_map_cache(), "(context norm. map cache)"); TagObject(context->embedder_data(), "(context data)"); - NATIVE_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD) - EXTRACT_CONTEXT_FIELD(OPTIMIZED_CODE_LIST, unused, optimized_code_list); - EXTRACT_CONTEXT_FIELD(DEOPTIMIZED_CODE_LIST, unused, deoptimized_code_list); -#undef EXTRACT_CONTEXT_FIELD + for (size_t i = 0; i < arraysize(native_context_names); i++) { + int index = native_context_names[i].index; + const char* name = native_context_names[i].name; + SetInternalReference(entry, name, context->get(index), + FixedArray::OffsetOfElementAt(index)); + } + + SetWeakReference( + entry, "optimized_code_list", + context->get(Context::OPTIMIZED_CODE_LIST), + FixedArray::OffsetOfElementAt(Context::OPTIMIZED_CODE_LIST)); + SetWeakReference( + entry, "deoptimized_code_list", + context->get(Context::DEOPTIMIZED_CODE_LIST), + FixedArray::OffsetOfElementAt(Context::DEOPTIMIZED_CODE_LIST)); STATIC_ASSERT(Context::OPTIMIZED_CODE_LIST == Context::FIRST_WEAK_SLOT); STATIC_ASSERT(Context::NEXT_CONTEXT_LINK + 1 == Context::NATIVE_CONTEXT_SLOTS); @@ -1140,17 +979,15 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) { } } - -void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { +void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) { MaybeObject* maybe_raw_transitions_or_prototype_info = map->raw_transitions(); HeapObject* raw_transitions_or_prototype_info; - if (maybe_raw_transitions_or_prototype_info->ToWeakHeapObject( + if (maybe_raw_transitions_or_prototype_info->GetHeapObjectIfWeak( &raw_transitions_or_prototype_info)) { DCHECK(raw_transitions_or_prototype_info->IsMap()); - SetWeakReference(map, entry, "transition", - raw_transitions_or_prototype_info, + SetWeakReference(entry, "transition", raw_transitions_or_prototype_info, Map::kTransitionsOrPrototypeInfoOffset); - } else if (maybe_raw_transitions_or_prototype_info->ToStrongHeapObject( + } else if (maybe_raw_transitions_or_prototype_info->GetHeapObjectIfStrong( &raw_transitions_or_prototype_info)) { if (raw_transitions_or_prototype_info->IsTransitionArray()) { TransitionArray* transitions = @@ -1160,55 +997,52 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { "(prototype transitions)"); } TagObject(transitions, "(transition array)"); - SetInternalReference(map, entry, "transitions", transitions, + SetInternalReference(entry, "transitions", transitions, Map::kTransitionsOrPrototypeInfoOffset); } else if (raw_transitions_or_prototype_info->IsTuple3() || raw_transitions_or_prototype_info->IsFixedArray()) { TagObject(raw_transitions_or_prototype_info, "(transition)"); - SetInternalReference(map, entry, "transition", + SetInternalReference(entry, "transition", raw_transitions_or_prototype_info, Map::kTransitionsOrPrototypeInfoOffset); } else if (map->is_prototype_map()) { TagObject(raw_transitions_or_prototype_info, "prototype_info"); - SetInternalReference(map, entry, "prototype_info", + SetInternalReference(entry, "prototype_info", raw_transitions_or_prototype_info, Map::kTransitionsOrPrototypeInfoOffset); } } DescriptorArray* descriptors = map->instance_descriptors(); TagObject(descriptors, "(map descriptors)"); - SetInternalReference(map, entry, "descriptors", descriptors, + SetInternalReference(entry, "descriptors", descriptors, Map::kDescriptorsOffset); - SetInternalReference(map, entry, "prototype", map->prototype(), + SetInternalReference(entry, "prototype", map->prototype(), Map::kPrototypeOffset); if (FLAG_unbox_double_fields) { - SetInternalReference(map, entry, "layout_descriptor", - map->layout_descriptor(), + SetInternalReference(entry, "layout_descriptor", map->layout_descriptor(), Map::kLayoutDescriptorOffset); } Object* constructor_or_backpointer = map->constructor_or_backpointer(); if (constructor_or_backpointer->IsMap()) { TagObject(constructor_or_backpointer, "(back pointer)"); - SetInternalReference(map, entry, "back_pointer", constructor_or_backpointer, + SetInternalReference(entry, "back_pointer", constructor_or_backpointer, Map::kConstructorOrBackPointerOffset); } else if (constructor_or_backpointer->IsFunctionTemplateInfo()) { TagObject(constructor_or_backpointer, "(constructor function data)"); - SetInternalReference(map, entry, "constructor_function_data", + SetInternalReference(entry, "constructor_function_data", constructor_or_backpointer, Map::kConstructorOrBackPointerOffset); } else { - SetInternalReference(map, entry, "constructor", constructor_or_backpointer, + SetInternalReference(entry, "constructor", constructor_or_backpointer, Map::kConstructorOrBackPointerOffset); } TagObject(map->dependent_code(), "(dependent code)"); - SetInternalReference(map, entry, "dependent_code", map->dependent_code(), + SetInternalReference(entry, "dependent_code", map->dependent_code(), Map::kDependentCodeOffset); } - void V8HeapExplorer::ExtractSharedFunctionInfoReferences( - int entry, SharedFunctionInfo* shared) { - HeapObject* obj = shared; + HeapEntry* entry, SharedFunctionInfo* shared) { String* shared_name = shared->DebugName(); const char* name = nullptr; if (shared_name != ReadOnlyRoots(heap_).empty_string()) { @@ -1223,59 +1057,51 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences( if (shared->name_or_scope_info()->IsScopeInfo()) { TagObject(shared->name_or_scope_info(), "(function scope info)"); } - SetInternalReference(obj, entry, "name_or_scope_info", + SetInternalReference(entry, "name_or_scope_info", shared->name_or_scope_info(), SharedFunctionInfo::kNameOrScopeInfoOffset); - SetInternalReference(obj, entry, "script_or_debug_info", + SetInternalReference(entry, "script_or_debug_info", shared->script_or_debug_info(), SharedFunctionInfo::kScriptOrDebugInfoOffset); - SetInternalReference(obj, entry, - "function_data", shared->function_data(), + SetInternalReference(entry, "function_data", shared->function_data(), SharedFunctionInfo::kFunctionDataOffset); SetInternalReference( - obj, entry, "raw_outer_scope_info_or_feedback_metadata", + entry, "raw_outer_scope_info_or_feedback_metadata", shared->raw_outer_scope_info_or_feedback_metadata(), SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset); } -void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) { - HeapObject* obj = script; - SetInternalReference(obj, entry, - "source", script->source(), +void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) { + SetInternalReference(entry, "source", script->source(), Script::kSourceOffset); - SetInternalReference(obj, entry, - "name", script->name(), - Script::kNameOffset); - SetInternalReference(obj, entry, - "context_data", script->context_data(), + SetInternalReference(entry, "name", script->name(), Script::kNameOffset); + SetInternalReference(entry, "context_data", script->context_data(), Script::kContextOffset); TagObject(script->line_ends(), "(script line ends)"); - SetInternalReference(obj, entry, - "line_ends", script->line_ends(), + SetInternalReference(entry, "line_ends", script->line_ends(), Script::kLineEndsOffset); } - void V8HeapExplorer::ExtractAccessorInfoReferences( - int entry, AccessorInfo* accessor_info) { - SetInternalReference(accessor_info, entry, "name", accessor_info->name(), + HeapEntry* entry, AccessorInfo* accessor_info) { + SetInternalReference(entry, "name", accessor_info->name(), AccessorInfo::kNameOffset); - SetInternalReference(accessor_info, entry, "expected_receiver_type", + SetInternalReference(entry, "expected_receiver_type", accessor_info->expected_receiver_type(), AccessorInfo::kExpectedReceiverTypeOffset); - SetInternalReference(accessor_info, entry, "getter", accessor_info->getter(), + SetInternalReference(entry, "getter", accessor_info->getter(), AccessorInfo::kGetterOffset); - SetInternalReference(accessor_info, entry, "setter", accessor_info->setter(), + SetInternalReference(entry, "setter", accessor_info->setter(), AccessorInfo::kSetterOffset); - SetInternalReference(accessor_info, entry, "data", accessor_info->data(), + SetInternalReference(entry, "data", accessor_info->data(), AccessorInfo::kDataOffset); } -void V8HeapExplorer::ExtractAccessorPairReferences( - int entry, AccessorPair* accessors) { - SetInternalReference(accessors, entry, "getter", accessors->getter(), +void V8HeapExplorer::ExtractAccessorPairReferences(HeapEntry* entry, + AccessorPair* accessors) { + SetInternalReference(entry, "getter", accessors->getter(), AccessorPair::kGetterOffset); - SetInternalReference(accessors, entry, "setter", accessors->setter(), + SetInternalReference(entry, "setter", accessors->setter(), AccessorPair::kSetterOffset); } @@ -1291,58 +1117,56 @@ void V8HeapExplorer::TagCodeObject(Code* code) { } } -void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) { +void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code* code) { TagCodeObject(code); TagObject(code->relocation_info(), "(code relocation info)"); - SetInternalReference(code, entry, - "relocation_info", code->relocation_info(), + SetInternalReference(entry, "relocation_info", code->relocation_info(), Code::kRelocationInfoOffset); TagObject(code->deoptimization_data(), "(code deopt data)"); - SetInternalReference(code, entry, - "deoptimization_data", code->deoptimization_data(), + SetInternalReference(entry, "deoptimization_data", + code->deoptimization_data(), Code::kDeoptimizationDataOffset); TagObject(code->source_position_table(), "(source position table)"); - SetInternalReference(code, entry, "source_position_table", + SetInternalReference(entry, "source_position_table", code->source_position_table(), Code::kSourcePositionTableOffset); } -void V8HeapExplorer::ExtractCellReferences(int entry, Cell* cell) { - SetInternalReference(cell, entry, "value", cell->value(), Cell::kValueOffset); +void V8HeapExplorer::ExtractCellReferences(HeapEntry* entry, Cell* cell) { + SetInternalReference(entry, "value", cell->value(), Cell::kValueOffset); } void V8HeapExplorer::ExtractFeedbackCellReferences( - int entry, FeedbackCell* feedback_cell) { + HeapEntry* entry, FeedbackCell* feedback_cell) { TagObject(feedback_cell, "(feedback cell)"); - SetInternalReference(feedback_cell, entry, "value", feedback_cell->value(), + SetInternalReference(entry, "value", feedback_cell->value(), FeedbackCell::kValueOffset); } -void V8HeapExplorer::ExtractPropertyCellReferences(int entry, +void V8HeapExplorer::ExtractPropertyCellReferences(HeapEntry* entry, PropertyCell* cell) { - SetInternalReference(cell, entry, "value", cell->value(), + SetInternalReference(entry, "value", cell->value(), PropertyCell::kValueOffset); TagObject(cell->dependent_code(), "(dependent code)"); - SetInternalReference(cell, entry, "dependent_code", cell->dependent_code(), + SetInternalReference(entry, "dependent_code", cell->dependent_code(), PropertyCell::kDependentCodeOffset); } -void V8HeapExplorer::ExtractAllocationSiteReferences(int entry, +void V8HeapExplorer::ExtractAllocationSiteReferences(HeapEntry* entry, AllocationSite* site) { - SetInternalReference(site, entry, "transition_info", + SetInternalReference(entry, "transition_info", site->transition_info_or_boilerplate(), AllocationSite::kTransitionInfoOrBoilerplateOffset); - SetInternalReference(site, entry, "nested_site", site->nested_site(), + SetInternalReference(entry, "nested_site", site->nested_site(), AllocationSite::kNestedSiteOffset); TagObject(site->dependent_code(), "(dependent code)"); - SetInternalReference(site, entry, "dependent_code", site->dependent_code(), + SetInternalReference(entry, "dependent_code", site->dependent_code(), AllocationSite::kDependentCodeOffset); } void V8HeapExplorer::ExtractArrayBoilerplateDescriptionReferences( - int entry, ArrayBoilerplateDescription* value) { - SetInternalReference(value, entry, "constant_elements", - value->constant_elements(), + HeapEntry* entry, ArrayBoilerplateDescription* value) { + SetInternalReference(entry, "constant_elements", value->constant_elements(), ArrayBoilerplateDescription::kConstantElementsOffset); } @@ -1352,7 +1176,7 @@ class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator { : size_(size) , explorer_(explorer) { } - virtual HeapEntry* AllocateEntry(HeapThing ptr) { + HeapEntry* AllocateEntry(HeapThing ptr) override { return explorer_->AddEntry(reinterpret_cast<Address>(ptr), HeapEntry::kNative, "system / JSArrayBufferData", size_); @@ -1362,73 +1186,74 @@ class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator { V8HeapExplorer* explorer_; }; -void V8HeapExplorer::ExtractJSArrayBufferReferences( - int entry, JSArrayBuffer* buffer) { +void V8HeapExplorer::ExtractJSArrayBufferReferences(HeapEntry* entry, + JSArrayBuffer* buffer) { // Setup a reference to a native memory backing_store object. if (!buffer->backing_store()) return; - size_t data_size = NumberToSize(buffer->byte_length()); + size_t data_size = buffer->byte_length(); JSArrayBufferDataEntryAllocator allocator(data_size, this); HeapEntry* data_entry = - filler_->FindOrAddEntry(buffer->backing_store(), &allocator); - filler_->SetNamedReference(HeapGraphEdge::kInternal, - entry, "backing_store", data_entry); + generator_->FindOrAddEntry(buffer->backing_store(), &allocator); + entry->SetNamedReference(HeapGraphEdge::kInternal, "backing_store", + data_entry); } -void V8HeapExplorer::ExtractJSPromiseReferences(int entry, JSPromise* promise) { - SetInternalReference(promise, entry, "reactions_or_result", +void V8HeapExplorer::ExtractJSPromiseReferences(HeapEntry* entry, + JSPromise* promise) { + SetInternalReference(entry, "reactions_or_result", promise->reactions_or_result(), JSPromise::kReactionsOrResultOffset); } void V8HeapExplorer::ExtractJSGeneratorObjectReferences( - int entry, JSGeneratorObject* generator) { - SetInternalReference(generator, entry, "function", generator->function(), + HeapEntry* entry, JSGeneratorObject* generator) { + SetInternalReference(entry, "function", generator->function(), JSGeneratorObject::kFunctionOffset); - SetInternalReference(generator, entry, "context", generator->context(), + SetInternalReference(entry, "context", generator->context(), JSGeneratorObject::kContextOffset); - SetInternalReference(generator, entry, "receiver", generator->receiver(), + SetInternalReference(entry, "receiver", generator->receiver(), JSGeneratorObject::kReceiverOffset); - SetInternalReference(generator, entry, "parameters_and_registers", + SetInternalReference(entry, "parameters_and_registers", generator->parameters_and_registers(), JSGeneratorObject::kParametersAndRegistersOffset); } -void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) { +void V8HeapExplorer::ExtractFixedArrayReferences(HeapEntry* entry, + FixedArray* array) { for (int i = 0, l = array->length(); i < l; ++i) { DCHECK(!HasWeakHeapObjectTag(array->get(i))); - SetInternalReference(array, entry, i, array->get(i), - array->OffsetOfElementAt(i)); + SetInternalReference(entry, i, array->get(i), array->OffsetOfElementAt(i)); } } void V8HeapExplorer::ExtractFeedbackVectorReferences( - int entry, FeedbackVector* feedback_vector) { + HeapEntry* entry, FeedbackVector* feedback_vector) { MaybeObject* code = feedback_vector->optimized_code_weak_or_smi(); HeapObject* code_heap_object; - if (code->ToWeakHeapObject(&code_heap_object)) { - SetWeakReference(feedback_vector, entry, "optimized code", code_heap_object, + if (code->GetHeapObjectIfWeak(&code_heap_object)) { + SetWeakReference(entry, "optimized code", code_heap_object, FeedbackVector::kOptimizedCodeOffset); } } template <typename T> -void V8HeapExplorer::ExtractWeakArrayReferences(int header_size, int entry, - T* array) { +void V8HeapExplorer::ExtractWeakArrayReferences(int header_size, + HeapEntry* entry, T* array) { for (int i = 0; i < array->length(); ++i) { MaybeObject* object = array->Get(i); HeapObject* heap_object; - if (object->ToWeakHeapObject(&heap_object)) { - SetWeakReference(array, entry, i, heap_object, - header_size + i * kPointerSize); - } else if (object->ToStrongHeapObject(&heap_object)) { - SetInternalReference(array, entry, i, heap_object, + if (object->GetHeapObjectIfWeak(&heap_object)) { + SetWeakReference(entry, i, heap_object, header_size + i * kPointerSize); + } else if (object->GetHeapObjectIfStrong(&heap_object)) { + SetInternalReference(entry, i, heap_object, header_size + i * kPointerSize); } } } -void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) { +void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, + HeapEntry* entry) { Isolate* isolate = js_obj->GetIsolate(); if (js_obj->HasFastProperties()) { DescriptorArray* descs = js_obj->map()->instance_descriptors(); @@ -1446,12 +1271,12 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) { int field_offset = field_index.is_inobject() ? field_index.offset() : -1; - SetDataOrAccessorPropertyReference(details.kind(), js_obj, entry, k, - value, nullptr, field_offset); + SetDataOrAccessorPropertyReference(details.kind(), entry, k, value, + nullptr, field_offset); break; } case kDescriptor: - SetDataOrAccessorPropertyReference(details.kind(), js_obj, entry, + SetDataOrAccessorPropertyReference(details.kind(), entry, descs->GetKey(i), descs->GetStrongValue(i)); break; @@ -1464,14 +1289,12 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) { int length = dictionary->Capacity(); ReadOnlyRoots roots(isolate); for (int i = 0; i < length; ++i) { - if (dictionary->IsKey(roots, dictionary->KeyAt(i))) { - PropertyCell* cell = dictionary->CellAt(i); - Name* name = cell->name(); - Object* value = cell->value(); - PropertyDetails details = cell->property_details(); - SetDataOrAccessorPropertyReference(details.kind(), js_obj, entry, name, - value); - } + if (!dictionary->IsKey(roots, dictionary->KeyAt(i))) continue; + PropertyCell* cell = dictionary->CellAt(i); + Name* name = cell->name(); + Object* value = cell->value(); + PropertyDetails details = cell->property_details(); + SetDataOrAccessorPropertyReference(details.kind(), entry, name, value); } } else { NameDictionary* dictionary = js_obj->property_dictionary(); @@ -1479,36 +1302,33 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) { ReadOnlyRoots roots(isolate); for (int i = 0; i < length; ++i) { Object* k = dictionary->KeyAt(i); - if (dictionary->IsKey(roots, k)) { - Object* value = dictionary->ValueAt(i); - PropertyDetails details = dictionary->DetailsAt(i); - SetDataOrAccessorPropertyReference(details.kind(), js_obj, entry, - Name::cast(k), value); - } + if (!dictionary->IsKey(roots, k)) continue; + Object* value = dictionary->ValueAt(i); + PropertyDetails details = dictionary->DetailsAt(i); + SetDataOrAccessorPropertyReference(details.kind(), entry, Name::cast(k), + value); } } } - -void V8HeapExplorer::ExtractAccessorPairProperty(JSObject* js_obj, int entry, - Name* key, +void V8HeapExplorer::ExtractAccessorPairProperty(HeapEntry* entry, Name* key, Object* callback_obj, int field_offset) { if (!callback_obj->IsAccessorPair()) return; AccessorPair* accessors = AccessorPair::cast(callback_obj); - SetPropertyReference(js_obj, entry, key, accessors, nullptr, field_offset); + SetPropertyReference(entry, key, accessors, nullptr, field_offset); Object* getter = accessors->getter(); if (!getter->IsOddball()) { - SetPropertyReference(js_obj, entry, key, getter, "get %s"); + SetPropertyReference(entry, key, getter, "get %s"); } Object* setter = accessors->setter(); if (!setter->IsOddball()) { - SetPropertyReference(js_obj, entry, key, setter, "set %s"); + SetPropertyReference(entry, key, setter, "set %s"); } } - -void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) { +void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, + HeapEntry* entry) { ReadOnlyRoots roots = js_obj->GetReadOnlyRoots(); if (js_obj->HasObjectElements()) { FixedArray* elements = FixedArray::cast(js_obj->elements()); @@ -1517,7 +1337,7 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) { : elements->length(); for (int i = 0; i < length; ++i) { if (!elements->get(i)->IsTheHole(roots)) { - SetElementReference(js_obj, entry, i, elements->get(i)); + SetElementReference(entry, i, elements->get(i)); } } } else if (js_obj->HasDictionaryElements()) { @@ -1525,22 +1345,20 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) { int length = dictionary->Capacity(); for (int i = 0; i < length; ++i) { Object* k = dictionary->KeyAt(i); - if (dictionary->IsKey(roots, k)) { - DCHECK(k->IsNumber()); - uint32_t index = static_cast<uint32_t>(k->Number()); - SetElementReference(js_obj, entry, index, dictionary->ValueAt(i)); - } + if (!dictionary->IsKey(roots, k)) continue; + DCHECK(k->IsNumber()); + uint32_t index = static_cast<uint32_t>(k->Number()); + SetElementReference(entry, index, dictionary->ValueAt(i)); } } } - -void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, int entry) { +void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, + HeapEntry* entry) { int length = js_obj->GetEmbedderFieldCount(); for (int i = 0; i < length; ++i) { Object* o = js_obj->GetEmbedderField(i); - SetInternalReference(js_obj, entry, i, o, - js_obj->GetEmbedderFieldOffset(i)); + SetInternalReference(entry, i, o, js_obj->GetEmbedderFieldOffset(i)); } } @@ -1564,10 +1382,8 @@ String* V8HeapExplorer::GetConstructorName(JSObject* object) { return *JSReceiver::GetConstructorName(handle(object, isolate)); } - HeapEntry* V8HeapExplorer::GetEntry(Object* obj) { - if (!obj->IsHeapObject()) return nullptr; - return filler_->FindOrAddEntry(obj, this); + return obj->IsHeapObject() ? generator_->FindOrAddEntry(obj, this) : nullptr; } class RootsReferencesExtractor : public RootVisitor { @@ -1597,8 +1413,9 @@ class RootsReferencesExtractor : public RootVisitor { bool visiting_weak_roots_; }; -bool V8HeapExplorer::IterateAndExtractReferences(SnapshotFiller* filler) { - filler_ = filler; +bool V8HeapExplorer::IterateAndExtractReferences( + HeapSnapshotGenerator* generator) { + generator_ = generator; // Create references to the synthetic roots. SetRootGcRootsReference(); @@ -1610,7 +1427,7 @@ bool V8HeapExplorer::IterateAndExtractReferences(SnapshotFiller* filler) { // first. Otherwise a particular JSFunction object could set // its custom name to a generic builtin. RootsReferencesExtractor extractor(this); - heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG); + heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG_FOR_SERIALIZATION); extractor.SetVisitingWeakRoots(); heap_->IterateWeakGlobalHandles(&extractor); @@ -1630,10 +1447,9 @@ bool V8HeapExplorer::IterateAndExtractReferences(SnapshotFiller* filler) { visited_fields_.resize(max_pointer, false); } - HeapEntry* heap_entry = GetEntry(obj); - int entry = heap_entry->index(); + HeapEntry* entry = GetEntry(obj); ExtractReferences(entry, obj); - SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); + SetInternalReference(entry, "map", obj->map(), HeapObject::kMapOffset); // Extract unvisited fields as hidden references and restore tags // of visited fields. IndexedReferencesExtractor refs_extractor(this, obj, entry); @@ -1650,7 +1466,7 @@ bool V8HeapExplorer::IterateAndExtractReferences(SnapshotFiller* filler) { if (!progress_->ProgressReport(false)) interrupted = true; } - filler_ = nullptr; + generator_ = nullptr; return interrupted ? false : progress_->ProgressReport(true); } @@ -1684,16 +1500,13 @@ bool V8HeapExplorer::IsEssentialHiddenReference(Object* parent, return true; } -void V8HeapExplorer::SetContextReference(HeapObject* parent_obj, - int parent_entry, +void V8HeapExplorer::SetContextReference(HeapEntry* parent_entry, String* reference_name, - Object* child_obj, - int field_offset) { - DCHECK(parent_entry == GetEntry(parent_obj)->index()); + Object* child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; - filler_->SetNamedReference(HeapGraphEdge::kContextVariable, parent_entry, - names_->GetName(reference_name), child_entry); + parent_entry->SetNamedReference(HeapGraphEdge::kContextVariable, + names_->GetName(reference_name), child_entry); MarkVisitedField(field_offset); } @@ -1704,135 +1517,98 @@ void V8HeapExplorer::MarkVisitedField(int offset) { visited_fields_[index] = true; } - -void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj, - int parent_entry, +void V8HeapExplorer::SetNativeBindReference(HeapEntry* parent_entry, const char* reference_name, Object* child_obj) { - DCHECK(parent_entry == GetEntry(parent_obj)->index()); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; - filler_->SetNamedReference(HeapGraphEdge::kShortcut, parent_entry, - reference_name, child_entry); + parent_entry->SetNamedReference(HeapGraphEdge::kShortcut, reference_name, + child_entry); } - -void V8HeapExplorer::SetElementReference(HeapObject* parent_obj, - int parent_entry, - int index, +void V8HeapExplorer::SetElementReference(HeapEntry* parent_entry, int index, Object* child_obj) { - DCHECK(parent_entry == GetEntry(parent_obj)->index()); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; - filler_->SetIndexedReference(HeapGraphEdge::kElement, parent_entry, index, - child_entry); + parent_entry->SetIndexedReference(HeapGraphEdge::kElement, index, + child_entry); } - -void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, - int parent_entry, +void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry, const char* reference_name, - Object* child_obj, - int field_offset) { - DCHECK(parent_entry == GetEntry(parent_obj)->index()); + Object* child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; if (IsEssentialObject(child_obj)) { - filler_->SetNamedReference(HeapGraphEdge::kInternal, - parent_entry, - reference_name, - child_entry); + parent_entry->SetNamedReference(HeapGraphEdge::kInternal, reference_name, + child_entry); } MarkVisitedField(field_offset); } - -void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, - int parent_entry, - int index, - Object* child_obj, - int field_offset) { - DCHECK(parent_entry == GetEntry(parent_obj)->index()); +void V8HeapExplorer::SetInternalReference(HeapEntry* parent_entry, int index, + Object* child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; if (IsEssentialObject(child_obj)) { - filler_->SetNamedReference(HeapGraphEdge::kInternal, - parent_entry, - names_->GetName(index), - child_entry); + parent_entry->SetNamedReference(HeapGraphEdge::kInternal, + names_->GetName(index), child_entry); } MarkVisitedField(field_offset); } void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, - int parent_entry, int index, + HeapEntry* parent_entry, int index, Object* child_obj, int field_offset) { - DCHECK(parent_entry == GetEntry(parent_obj)->index()); + DCHECK_EQ(parent_entry, GetEntry(parent_obj)); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry != nullptr && IsEssentialObject(child_obj) && IsEssentialHiddenReference(parent_obj, field_offset)) { - filler_->SetIndexedReference(HeapGraphEdge::kHidden, parent_entry, index, - child_entry); + parent_entry->SetIndexedReference(HeapGraphEdge::kHidden, index, + child_entry); } } - -void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, - int parent_entry, +void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry, const char* reference_name, - Object* child_obj, - int field_offset) { - DCHECK(parent_entry == GetEntry(parent_obj)->index()); + Object* child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; if (IsEssentialObject(child_obj)) { - filler_->SetNamedReference(HeapGraphEdge::kWeak, - parent_entry, - reference_name, - child_entry); + parent_entry->SetNamedReference(HeapGraphEdge::kWeak, reference_name, + child_entry); } MarkVisitedField(field_offset); } - -void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, - int parent_entry, - int index, - Object* child_obj, - int field_offset) { - DCHECK(parent_entry == GetEntry(parent_obj)->index()); +void V8HeapExplorer::SetWeakReference(HeapEntry* parent_entry, int index, + Object* child_obj, int field_offset) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; if (IsEssentialObject(child_obj)) { - filler_->SetNamedReference(HeapGraphEdge::kWeak, - parent_entry, - names_->GetFormatted("%d", index), - child_entry); + parent_entry->SetNamedReference( + HeapGraphEdge::kWeak, names_->GetFormatted("%d", index), child_entry); } MarkVisitedField(field_offset); } void V8HeapExplorer::SetDataOrAccessorPropertyReference( - PropertyKind kind, JSObject* parent_obj, int parent_entry, - Name* reference_name, Object* child_obj, const char* name_format_string, - int field_offset) { + PropertyKind kind, HeapEntry* parent_entry, Name* reference_name, + Object* child_obj, const char* name_format_string, int field_offset) { if (kind == kAccessor) { - ExtractAccessorPairProperty(parent_obj, parent_entry, reference_name, - child_obj, field_offset); + ExtractAccessorPairProperty(parent_entry, reference_name, child_obj, + field_offset); } else { - SetPropertyReference(parent_obj, parent_entry, reference_name, child_obj, + SetPropertyReference(parent_entry, reference_name, child_obj, name_format_string, field_offset); } } - -void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, - int parent_entry, +void V8HeapExplorer::SetPropertyReference(HeapEntry* parent_entry, Name* reference_name, Object* child_obj, const char* name_format_string, int field_offset) { - DCHECK(parent_entry == GetEntry(parent_obj)->index()); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; HeapGraphEdge::Type type = @@ -1848,29 +1624,25 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, .get()) : names_->GetName(reference_name); - filler_->SetNamedReference(type, parent_entry, name, child_entry); + parent_entry->SetNamedReference(type, name, child_entry); MarkVisitedField(field_offset); } void V8HeapExplorer::SetRootGcRootsReference() { - filler_->SetIndexedAutoIndexReference( - HeapGraphEdge::kElement, - snapshot_->root()->index(), - snapshot_->gc_roots()); + snapshot_->root()->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, + snapshot_->gc_roots()); } void V8HeapExplorer::SetUserGlobalReference(Object* child_obj) { HeapEntry* child_entry = GetEntry(child_obj); DCHECK_NOT_NULL(child_entry); - filler_->SetNamedAutoIndexReference(HeapGraphEdge::kShortcut, - snapshot_->root()->index(), nullptr, - child_entry); + snapshot_->root()->SetNamedAutoIndexReference(HeapGraphEdge::kShortcut, + nullptr, child_entry, names_); } void V8HeapExplorer::SetGcRootsReference(Root root) { - filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, - snapshot_->gc_roots()->index(), - snapshot_->gc_subroot(root)); + snapshot_->gc_roots()->SetIndexedAutoIndexReference( + HeapGraphEdge::kElement, snapshot_->gc_subroot(root)); } void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description, @@ -1881,12 +1653,11 @@ void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description, HeapGraphEdge::Type edge_type = is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kInternal; if (name != nullptr) { - filler_->SetNamedReference(edge_type, snapshot_->gc_subroot(root)->index(), - name, child_entry); + snapshot_->gc_subroot(root)->SetNamedReference(edge_type, name, + child_entry); } else { - filler_->SetNamedAutoIndexReference(edge_type, - snapshot_->gc_subroot(root)->index(), - description, child_entry); + snapshot_->gc_subroot(root)->SetNamedAutoIndexReference( + edge_type, description, child_entry, names_); } // Add a shortcut to JS global object reference at snapshot root. @@ -1897,53 +1668,34 @@ void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description, JSGlobalObject* global = Context::cast(child_obj)->global_object(); if (!global->IsJSGlobalObject()) return; - if (user_roots_.Contains(global)) return; + if (!user_roots_.insert(global).second) return; - user_roots_.Insert(global); SetUserGlobalReference(global); } -const char* V8HeapExplorer::GetStrongGcSubrootName(Object* object) { - ReadOnlyRoots roots(heap_); - if (strong_gc_subroot_names_.is_empty()) { -#define NAME_ENTRY(name) strong_gc_subroot_names_.SetTag(heap_->name(), #name); -#define RO_NAME_ENTRY(name) \ - strong_gc_subroot_names_.SetTag(roots.name(), #name); -#define ROOT_NAME(type, name, camel_name) NAME_ENTRY(name) - STRONG_MUTABLE_ROOT_LIST(ROOT_NAME) +// This static array is used to prevent excessive code-size in +// GetStrongGcSubrootName below, which would happen if we called emplace() for +// every root in a macro. +static const char* root_names[] = { +#define ROOT_NAME(type, name, CamelName) #name, + READ_ONLY_ROOT_LIST(ROOT_NAME) MUTABLE_ROOT_LIST(ROOT_NAME) #undef ROOT_NAME -#define ROOT_NAME(type, name, camel_name) RO_NAME_ENTRY(name) - STRONG_READ_ONLY_ROOT_LIST(ROOT_NAME) -#undef ROOT_NAME -#define STRUCT_MAP_NAME(NAME, Name, name) RO_NAME_ENTRY(name##_map) - STRUCT_LIST(STRUCT_MAP_NAME) -#undef STRUCT_MAP_NAME -#define ALLOCATION_SITE_MAP_NAME(NAME, Name, Size, name) \ - RO_NAME_ENTRY(name##_map) - ALLOCATION_SITE_LIST(ALLOCATION_SITE_MAP_NAME) -#undef ALLOCATION_SITE_MAP_NAME -#define DATA_HANDLER_MAP_NAME(NAME, Name, Size, name) NAME_ENTRY(name##_map) - DATA_HANDLER_LIST(DATA_HANDLER_MAP_NAME) -#undef DATA_HANDLER_MAP_NAME -#define STRING_NAME(name, str) RO_NAME_ENTRY(name) - INTERNALIZED_STRING_LIST(STRING_NAME) -#undef STRING_NAME -#define SYMBOL_NAME(name) RO_NAME_ENTRY(name) - PRIVATE_SYMBOL_LIST(SYMBOL_NAME) -#undef SYMBOL_NAME -#define SYMBOL_NAME(name, description) RO_NAME_ENTRY(name) - PUBLIC_SYMBOL_LIST(SYMBOL_NAME) - WELL_KNOWN_SYMBOL_LIST(SYMBOL_NAME) -#undef SYMBOL_NAME -#define ACCESSOR_NAME(accessor_name, AccessorName) \ - NAME_ENTRY(accessor_name##_accessor) - ACCESSOR_INFO_LIST(ACCESSOR_NAME) -#undef ACCESSOR_NAME -#undef NAME_ENTRY -#undef RO_NAME_ENTRY - CHECK(!strong_gc_subroot_names_.is_empty()); - } - return strong_gc_subroot_names_.GetTag(object); +}; +STATIC_ASSERT(static_cast<uint16_t>(RootIndex::kRootListLength) == + arraysize(root_names)); + +const char* V8HeapExplorer::GetStrongGcSubrootName(Object* object) { + if (strong_gc_subroot_names_.empty()) { + for (uint16_t i = 0; i < static_cast<uint16_t>(RootIndex::kRootListLength); + i++) { + const char* name = root_names[i]; + RootIndex index = static_cast<RootIndex>(i); + strong_gc_subroot_names_.emplace(heap_->root(index), name); + } + CHECK(!strong_gc_subroot_names_.empty()); + } + auto it = strong_gc_subroot_names_.find(object); + return it != strong_gc_subroot_names_.end() ? it->second : nullptr; } void V8HeapExplorer::TagObject(Object* obj, const char* tag) { @@ -1993,7 +1745,7 @@ void V8HeapExplorer::TagGlobalObjects() { DisallowHeapAllocation no_allocation; for (int i = 0, l = enumerator.count(); i < l; ++i) { - objects_tags_.SetTag(*enumerator.at(i), urls[i]); + if (urls[i]) objects_tags_.emplace(*enumerator.at(i), urls[i]); } } @@ -2055,7 +1807,7 @@ class GlobalHandlesExtractor : public PersistentHandleVisitor { public: explicit GlobalHandlesExtractor(NativeObjectsExplorer* explorer) : explorer_(explorer) {} - ~GlobalHandlesExtractor() override {} + ~GlobalHandlesExtractor() override = default; void VisitPersistentHandle(Persistent<Value>* value, uint16_t class_id) override { Handle<Object> object = Utils::OpenPersistent(value); @@ -2077,7 +1829,7 @@ class BasicHeapEntriesAllocator : public HeapEntriesAllocator { heap_object_map_(snapshot_->profiler()->heap_object_map()), entries_type_(entries_type) { } - virtual HeapEntry* AllocateEntry(HeapThing ptr); + HeapEntry* AllocateEntry(HeapThing ptr) override; private: HeapSnapshot* snapshot_; StringsStorage* names_; @@ -2108,7 +1860,7 @@ class EmbedderGraphEntriesAllocator : public HeapEntriesAllocator { : snapshot_(snapshot), names_(snapshot_->profiler()->names()), heap_object_map_(snapshot_->profiler()->heap_object_map()) {} - virtual HeapEntry* AllocateEntry(HeapThing ptr); + HeapEntry* AllocateEntry(HeapThing ptr) override; private: HeapSnapshot* snapshot_; @@ -2135,12 +1887,9 @@ HeapEntry::Type EmbedderGraphNodeType(EmbedderGraphImpl::Node* node) { // Otherwise, the result is the embedder node name. const char* MergeNames(StringsStorage* names, const char* embedder_name, const char* wrapper_name) { - for (const char* suffix = wrapper_name; *suffix; suffix++) { - if (*suffix == '/') { - return names->GetFormatted("%s %s", embedder_name, suffix); - } - } - return embedder_name; + const char* suffix = strchr(wrapper_name, '/'); + return suffix ? names->GetFormatted("%s %s", embedder_name, suffix) + : embedder_name; } } // anonymous namespace @@ -2163,17 +1912,17 @@ class NativeGroupRetainedObjectInfo : public v8::RetainedObjectInfo { hash_(reinterpret_cast<intptr_t>(label)), label_(label) {} - virtual ~NativeGroupRetainedObjectInfo() {} - virtual void Dispose() { + ~NativeGroupRetainedObjectInfo() override = default; + void Dispose() override { CHECK(!disposed_); disposed_ = true; delete this; } - virtual bool IsEquivalent(RetainedObjectInfo* other) { + bool IsEquivalent(RetainedObjectInfo* other) override { return hash_ == other->GetHash() && !strcmp(label_, other->GetLabel()); } - virtual intptr_t GetHash() { return hash_; } - virtual const char* GetLabel() { return label_; } + intptr_t GetHash() override { return hash_; } + const char* GetLabel() override { return label_; } private: bool disposed_; @@ -2193,8 +1942,7 @@ NativeObjectsExplorer::NativeObjectsExplorer( native_entries_allocator_( new BasicHeapEntriesAllocator(snapshot, HeapEntry::kNative)), embedder_graph_entries_allocator_( - new EmbedderGraphEntriesAllocator(snapshot)), - filler_(nullptr) {} + new EmbedderGraphEntriesAllocator(snapshot)) {} NativeObjectsExplorer::~NativeObjectsExplorer() { for (auto map_entry : objects_by_info_) { @@ -2231,7 +1979,7 @@ void NativeObjectsExplorer::FillRetainedObjects() { DCHECK(!object.is_null()); HeapObject* heap_object = HeapObject::cast(*object); info->push_back(heap_object); - in_groups_.Insert(heap_object); + in_groups_.insert(heap_object); } } @@ -2252,25 +2000,23 @@ void NativeObjectsExplorer::FillEdges() { Handle<Object> parent_object = v8::Utils::OpenHandle( *pair.first->Get(reinterpret_cast<v8::Isolate*>(isolate_))); HeapObject* parent = HeapObject::cast(*parent_object); - int parent_entry = - filler_->FindOrAddEntry(parent, native_entries_allocator_.get()) - ->index(); - DCHECK_NE(parent_entry, HeapEntry::kNoEntry); + HeapEntry* parent_entry = + generator_->FindOrAddEntry(parent, native_entries_allocator_.get()); + DCHECK_NOT_NULL(parent_entry); Handle<Object> child_object = v8::Utils::OpenHandle( *pair.second->Get(reinterpret_cast<v8::Isolate*>(isolate_))); HeapObject* child = HeapObject::cast(*child_object); HeapEntry* child_entry = - filler_->FindOrAddEntry(child, native_entries_allocator_.get()); - filler_->SetNamedReference(HeapGraphEdge::kInternal, parent_entry, "native", - child_entry); + generator_->FindOrAddEntry(child, native_entries_allocator_.get()); + parent_entry->SetNamedReference(HeapGraphEdge::kInternal, "native", + child_entry); } edges_.clear(); } std::vector<HeapObject*>* NativeObjectsExplorer::GetVectorMaybeDisposeInfo( v8::RetainedObjectInfo* info) { - auto map_entry = objects_by_info_.find(info); - if (map_entry != objects_by_info_.end()) { + if (objects_by_info_.count(info)) { info->Dispose(); } else { objects_by_info_[info] = new std::vector<HeapObject*>(); @@ -2285,21 +2031,20 @@ HeapEntry* NativeObjectsExplorer::EntryForEmbedderGraphNode( node = wrapper; } if (node->IsEmbedderNode()) { - return filler_->FindOrAddEntry(node, - embedder_graph_entries_allocator_.get()); + return generator_->FindOrAddEntry(node, + embedder_graph_entries_allocator_.get()); } else { EmbedderGraphImpl::V8NodeImpl* v8_node = static_cast<EmbedderGraphImpl::V8NodeImpl*>(node); Object* object = v8_node->GetObject(); if (object->IsSmi()) return nullptr; - HeapEntry* entry = filler_->FindEntry(HeapObject::cast(object)); - return entry; + return generator_->FindEntry(HeapObject::cast(object)); } } bool NativeObjectsExplorer::IterateAndExtractReferences( - SnapshotFiller* filler) { - filler_ = filler; + HeapSnapshotGenerator* generator) { + generator_ = generator; if (FLAG_heap_profiler_use_embedder_graph && snapshot_->profiler()->HasBuildEmbedderGraphCallback()) { @@ -2309,9 +2054,8 @@ bool NativeObjectsExplorer::IterateAndExtractReferences( snapshot_->profiler()->BuildEmbedderGraph(isolate_, &graph); for (const auto& node : graph.nodes()) { if (node->IsRootNode()) { - filler_->SetIndexedAutoIndexReference( - HeapGraphEdge::kElement, snapshot_->root()->index(), - EntryForEmbedderGraphNode(node.get())); + snapshot_->root()->SetIndexedAutoIndexReference( + HeapGraphEdge::kElement, EntryForEmbedderGraphNode(node.get())); } // Adjust the name and the type of the V8 wrapper node. auto wrapper = node->WrapperNode(); @@ -2326,21 +2070,15 @@ bool NativeObjectsExplorer::IterateAndExtractReferences( // Fill edges of the graph. for (const auto& edge : graph.edges()) { HeapEntry* from = EntryForEmbedderGraphNode(edge.from); - // The |from| and |to| can nullptr if the corrsponding node is a V8 node + // |from| and |to| can be nullptr if the corresponding node is a V8 node // pointing to a Smi. if (!from) continue; - // Adding an entry for |edge.to| can invalidate the |from| entry because - // it is an address in std::vector. Use index instead of pointer. - int from_index = from->index(); HeapEntry* to = EntryForEmbedderGraphNode(edge.to); - if (to) { - if (edge.name == nullptr) { - filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, - from_index, to); - } else { - filler_->SetNamedReference(HeapGraphEdge::kInternal, from_index, - edge.name, to); - } + if (!to) continue; + if (edge.name == nullptr) { + from->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, to); + } else { + from->SetNamedReference(HeapGraphEdge::kInternal, edge.name, to); } } } else { @@ -2358,15 +2096,14 @@ bool NativeObjectsExplorer::IterateAndExtractReferences( SetRootNativeRootsReference(); } } - filler_ = nullptr; + generator_ = nullptr; return true; } NativeGroupRetainedObjectInfo* NativeObjectsExplorer::FindOrAddGroupInfo( const char* label) { const char* label_copy = names_->GetCopy(label); - auto map_entry = native_groups_.find(label_copy); - if (map_entry == native_groups_.end()) { + if (!native_groups_.count(label_copy)) { native_groups_[label_copy] = new NativeGroupRetainedObjectInfo(label); } return native_groups_[label_copy]; @@ -2375,61 +2112,48 @@ NativeGroupRetainedObjectInfo* NativeObjectsExplorer::FindOrAddGroupInfo( void NativeObjectsExplorer::SetNativeRootReference( v8::RetainedObjectInfo* info) { HeapEntry* child_entry = - filler_->FindOrAddEntry(info, native_entries_allocator_.get()); + generator_->FindOrAddEntry(info, native_entries_allocator_.get()); DCHECK_NOT_NULL(child_entry); NativeGroupRetainedObjectInfo* group_info = FindOrAddGroupInfo(info->GetGroupLabel()); - HeapEntry* group_entry = - filler_->FindOrAddEntry(group_info, synthetic_entries_allocator_.get()); - // |FindOrAddEntry| can move and resize the entries backing store. Reload - // potentially-stale pointer. - child_entry = filler_->FindEntry(info); - filler_->SetNamedAutoIndexReference( - HeapGraphEdge::kInternal, group_entry->index(), nullptr, child_entry); + HeapEntry* group_entry = generator_->FindOrAddEntry( + group_info, synthetic_entries_allocator_.get()); + group_entry->SetNamedAutoIndexReference(HeapGraphEdge::kInternal, nullptr, + child_entry, names_); } - void NativeObjectsExplorer::SetWrapperNativeReferences( HeapObject* wrapper, v8::RetainedObjectInfo* info) { - HeapEntry* wrapper_entry = filler_->FindEntry(wrapper); + HeapEntry* wrapper_entry = generator_->FindEntry(wrapper); DCHECK_NOT_NULL(wrapper_entry); HeapEntry* info_entry = - filler_->FindOrAddEntry(info, native_entries_allocator_.get()); + generator_->FindOrAddEntry(info, native_entries_allocator_.get()); DCHECK_NOT_NULL(info_entry); - filler_->SetNamedReference(HeapGraphEdge::kInternal, - wrapper_entry->index(), - "native", - info_entry); - filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, - info_entry->index(), - wrapper_entry); + wrapper_entry->SetNamedReference(HeapGraphEdge::kInternal, "native", + info_entry); + info_entry->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, + wrapper_entry); } - void NativeObjectsExplorer::SetRootNativeRootsReference() { for (auto map_entry : native_groups_) { NativeGroupRetainedObjectInfo* group_info = map_entry.second; HeapEntry* group_entry = - filler_->FindOrAddEntry(group_info, native_entries_allocator_.get()); + generator_->FindOrAddEntry(group_info, native_entries_allocator_.get()); DCHECK_NOT_NULL(group_entry); - filler_->SetIndexedAutoIndexReference( - HeapGraphEdge::kElement, - snapshot_->root()->index(), - group_entry); + snapshot_->root()->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, + group_entry); } } - void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) { - if (in_groups_.Contains(*p)) return; - Isolate* isolate = isolate_; + if (in_groups_.count(*p)) return; v8::RetainedObjectInfo* info = - isolate->heap_profiler()->ExecuteWrapperClassCallback(class_id, p); + isolate_->heap_profiler()->ExecuteWrapperClassCallback(class_id, p); if (info == nullptr) return; GetVectorMaybeDisposeInfo(info)->push_back(HeapObject::cast(*p)); } - HeapSnapshotGenerator::HeapSnapshotGenerator( HeapSnapshot* snapshot, v8::ActivityControl* control, @@ -2464,10 +2188,10 @@ bool HeapSnapshotGenerator::GenerateSnapshot() { // full GC is reachable from the root when computing dominators. // This is not true for weakly reachable objects. // As a temporary solution we call GC twice. - heap_->CollectAllGarbage(Heap::kMakeHeapIterableMask, - GarbageCollectionReason::kHeapProfiler); - heap_->CollectAllGarbage(Heap::kMakeHeapIterableMask, - GarbageCollectionReason::kHeapProfiler); + heap_->PreciseCollectAllGarbage(Heap::kNoGCFlags, + GarbageCollectionReason::kHeapProfiler); + heap_->PreciseCollectAllGarbage(Heap::kNoGCFlags, + GarbageCollectionReason::kHeapProfiler); NullContextScope null_context_scope(heap_->isolate()); @@ -2525,12 +2249,10 @@ void HeapSnapshotGenerator::InitProgressCounter() { } bool HeapSnapshotGenerator::FillReferences() { - SnapshotFiller filler(snapshot_, &entries_); - return v8_heap_explorer_.IterateAndExtractReferences(&filler) && - dom_explorer_.IterateAndExtractReferences(&filler); + return v8_heap_explorer_.IterateAndExtractReferences(this) && + dom_explorer_.IterateAndExtractReferences(this); } - template<int bytes> struct MaxDecimalDigitsIn; template<> struct MaxDecimalDigitsIn<4> { static const int kSigned = 11; @@ -2541,7 +2263,6 @@ template<> struct MaxDecimalDigitsIn<8> { static const int kUnsigned = 20; }; - class OutputStreamWriter { public: explicit OutputStreamWriter(v8::OutputStream* stream) @@ -2765,9 +2486,8 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge, writer_->AddString(buffer.start()); } - void HeapSnapshotJSONSerializer::SerializeEdges() { - std::deque<HeapGraphEdge*>& edges = snapshot_->children(); + std::vector<HeapGraphEdge*>& edges = snapshot_->children(); for (size_t i = 0; i < edges.size(); ++i) { DCHECK(i == 0 || edges[i - 1]->from()->index() <= edges[i]->from()->index()); @@ -2803,16 +2523,14 @@ void HeapSnapshotJSONSerializer::SerializeNode(const HeapEntry* entry) { writer_->AddString(buffer.start()); } - void HeapSnapshotJSONSerializer::SerializeNodes() { - std::vector<HeapEntry>& entries = snapshot_->entries(); + const std::deque<HeapEntry>& entries = snapshot_->entries(); for (const HeapEntry& entry : entries) { SerializeNode(&entry); if (writer_->aborted()) return; } } - void HeapSnapshotJSONSerializer::SerializeSnapshot() { writer_->AddString("\"meta\":"); // The object describing node serialization layout. diff --git a/deps/v8/src/profiler/heap-snapshot-generator.h b/deps/v8/src/profiler/heap-snapshot-generator.h index f25bee9f46..1f8f364912 100644 --- a/deps/v8/src/profiler/heap-snapshot-generator.h +++ b/deps/v8/src/profiler/heap-snapshot-generator.h @@ -7,6 +7,7 @@ #include <deque> #include <unordered_map> +#include <unordered_set> #include <vector> #include "include/v8-profiler.h" @@ -28,10 +29,14 @@ class HeapEntry; class HeapIterator; class HeapProfiler; class HeapSnapshot; +class HeapSnapshotGenerator; class JSArrayBuffer; class JSCollection; +class JSGeneratorObject; +class JSGlobalObject; +class JSGlobalProxy; +class JSPromise; class JSWeakCollection; -class SnapshotFiller; struct SourceLocation { SourceLocation(int entry_index, int scriptId, int line, int col) @@ -43,7 +48,7 @@ struct SourceLocation { const int col; }; -class HeapGraphEdge BASE_EMBEDDED { +class HeapGraphEdge { public: enum Type { kContextVariable = v8::HeapGraphEdge::kContextVariable, @@ -55,9 +60,8 @@ class HeapGraphEdge BASE_EMBEDDED { kWeak = v8::HeapGraphEdge::kWeak }; - HeapGraphEdge(Type type, const char* name, int from, int to); - HeapGraphEdge(Type type, int index, int from, int to); - void ReplaceToIndexWithEntry(HeapSnapshot* snapshot); + HeapGraphEdge(Type type, const char* name, HeapEntry* from, HeapEntry* to); + HeapGraphEdge(Type type, int index, HeapEntry* from, HeapEntry* to); Type type() const { return TypeField::decode(bit_field_); } int index() const { @@ -81,12 +85,7 @@ class HeapGraphEdge BASE_EMBEDDED { class TypeField : public BitField<Type, 0, 3> {}; class FromIndexField : public BitField<int, 3, 29> {}; uint32_t bit_field_; - union { - // During entries population |to_index_| is used for storing the index, - // afterwards it is replaced with a pointer to the entry. - int to_index_; - HeapEntry* to_entry_; - }; + HeapEntry* to_entry_; union { int index_; const char* name_; @@ -96,7 +95,7 @@ class HeapGraphEdge BASE_EMBEDDED { // HeapEntry instances represent an entity from the heap (or a special // virtual node, e.g. root). -class HeapEntry BASE_EMBEDDED { +class HeapEntry { public: enum Type { kHidden = v8::HeapGraphNode::kHidden, @@ -114,15 +113,9 @@ class HeapEntry BASE_EMBEDDED { kSymbol = v8::HeapGraphNode::kSymbol, kBigInt = v8::HeapGraphNode::kBigInt }; - static const int kNoEntry; - HeapEntry() { } - HeapEntry(HeapSnapshot* snapshot, - Type type, - const char* name, - SnapshotObjectId id, - size_t self_size, - unsigned trace_node_id); + HeapEntry(HeapSnapshot* snapshot, int index, Type type, const char* name, + SnapshotObjectId id, size_t self_size, unsigned trace_node_id); HeapSnapshot* snapshot() { return snapshot_; } Type type() const { return static_cast<Type>(type_); } @@ -132,8 +125,8 @@ class HeapEntry BASE_EMBEDDED { SnapshotObjectId id() const { return id_; } size_t self_size() const { return self_size_; } unsigned trace_node_id() const { return trace_node_id_; } - V8_INLINE int index() const; - int children_count() const { return children_count_; } + int index() const { return index_; } + V8_INLINE int children_count() const; V8_INLINE int set_children_index(int index); V8_INLINE void add_child(HeapGraphEdge* edge); V8_INLINE HeapGraphEdge* child(int i); @@ -143,18 +136,30 @@ class HeapEntry BASE_EMBEDDED { HeapGraphEdge::Type type, int index, HeapEntry* entry); void SetNamedReference( HeapGraphEdge::Type type, const char* name, HeapEntry* entry); + void SetIndexedAutoIndexReference(HeapGraphEdge::Type type, + HeapEntry* child) { + SetIndexedReference(type, children_count_ + 1, child); + } + void SetNamedAutoIndexReference(HeapGraphEdge::Type type, + const char* description, HeapEntry* child, + StringsStorage* strings); void Print( const char* prefix, const char* edge_name, int max_depth, int indent); private: - V8_INLINE std::deque<HeapGraphEdge*>::iterator children_begin(); - V8_INLINE std::deque<HeapGraphEdge*>::iterator children_end(); + V8_INLINE std::vector<HeapGraphEdge*>::iterator children_begin() const; + V8_INLINE std::vector<HeapGraphEdge*>::iterator children_end() const; const char* TypeAsString(); unsigned type_: 4; - int children_count_: 28; - int children_index_; + unsigned index_ : 28; // Supports up to ~250M objects. + union { + // The count is used during the snapshot build phase, + // then it gets converted into the index by the |FillChildren| function. + unsigned children_count_; + unsigned children_end_index_; + }; size_t self_size_; HeapSnapshot* snapshot_; const char* name_; @@ -163,7 +168,6 @@ class HeapEntry BASE_EMBEDDED { unsigned trace_node_id_; }; - // HeapSnapshot represents a single heap snapshot. It is stored in // HeapProfiler, which is also a factory for // HeapSnapshots. All HeapSnapshots share strings copied from JS heap @@ -174,22 +178,23 @@ class HeapSnapshot { explicit HeapSnapshot(HeapProfiler* profiler); void Delete(); - HeapProfiler* profiler() { return profiler_; } - HeapEntry* root() { return &entries_[root_index_]; } - HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; } - HeapEntry* gc_subroot(Root root) { - return &entries_[gc_subroot_indexes_[static_cast<int>(root)]]; + HeapProfiler* profiler() const { return profiler_; } + HeapEntry* root() const { return root_entry_; } + HeapEntry* gc_roots() const { return gc_roots_entry_; } + HeapEntry* gc_subroot(Root root) const { + return gc_subroot_entries_[static_cast<int>(root)]; } - std::vector<HeapEntry>& entries() { return entries_; } + std::deque<HeapEntry>& entries() { return entries_; } std::deque<HeapGraphEdge>& edges() { return edges_; } - std::deque<HeapGraphEdge*>& children() { return children_; } + std::vector<HeapGraphEdge*>& children() { return children_; } const std::vector<SourceLocation>& locations() const { return locations_; } void RememberLastJSObjectId(); SnapshotObjectId max_snapshot_js_object_id() const { return max_snapshot_js_object_id_; } + bool is_complete() const { return !children_.empty(); } - void AddLocation(int entry, int scriptId, int line, int col); + void AddLocation(HeapEntry* entry, int scriptId, int line, int col); HeapEntry* AddEntry(HeapEntry::Type type, const char* name, SnapshotObjectId id, @@ -197,28 +202,28 @@ class HeapSnapshot { unsigned trace_node_id); void AddSyntheticRootEntries(); HeapEntry* GetEntryById(SnapshotObjectId id); - std::vector<HeapEntry*>* GetSortedEntriesList(); void FillChildren(); void Print(int max_depth); private: - HeapEntry* AddRootEntry(); - HeapEntry* AddGcRootsEntry(); - HeapEntry* AddGcSubrootEntry(Root root, SnapshotObjectId id); + void AddRootEntry(); + void AddGcRootsEntry(); + void AddGcSubrootEntry(Root root, SnapshotObjectId id); HeapProfiler* profiler_; - int root_index_; - int gc_roots_index_; - int gc_subroot_indexes_[static_cast<int>(Root::kNumberOfRoots)]; - std::vector<HeapEntry> entries_; + HeapEntry* root_entry_ = nullptr; + HeapEntry* gc_roots_entry_ = nullptr; + HeapEntry* gc_subroot_entries_[static_cast<int>(Root::kNumberOfRoots)]; + // For |entries_| we rely on the deque property, that it never reallocates + // backing storage, thus all entry pointers remain valid for the duration + // of snapshotting. + std::deque<HeapEntry> entries_; std::deque<HeapGraphEdge> edges_; - std::deque<HeapGraphEdge*> children_; - std::vector<HeapEntry*> sorted_entries_; + std::vector<HeapGraphEdge*> children_; + std::unordered_map<SnapshotObjectId, HeapEntry*> entries_by_id_cache_; std::vector<SourceLocation> locations_; - SnapshotObjectId max_snapshot_js_object_id_; - - friend class HeapSnapshotTester; + SnapshotObjectId max_snapshot_js_object_id_ = -1; DISALLOW_COPY_AND_ASSIGN(HeapSnapshot); }; @@ -294,68 +299,28 @@ typedef void* HeapThing; // An interface that creates HeapEntries by HeapThings. class HeapEntriesAllocator { public: - virtual ~HeapEntriesAllocator() { } + virtual ~HeapEntriesAllocator() = default; virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0; }; -// The HeapEntriesMap instance is used to track a mapping between -// real heap objects and their representations in heap snapshots. -class HeapEntriesMap { - public: - HeapEntriesMap(); - - int Map(HeapThing thing); - void Pair(HeapThing thing, int entry); - - private: - static uint32_t Hash(HeapThing thing) { - return ComputeUnseededHash( - static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing))); - } - - base::HashMap entries_; - - friend class HeapObjectsSet; - - DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap); -}; - - -class HeapObjectsSet { - public: - HeapObjectsSet(); - void Clear(); - bool Contains(Object* object); - void Insert(Object* obj); - const char* GetTag(Object* obj); - void SetTag(Object* obj, const char* tag); - bool is_empty() const { return entries_.occupancy() == 0; } - - private: - base::HashMap entries_; - - DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet); -}; - - class SnapshottingProgressReportingInterface { public: - virtual ~SnapshottingProgressReportingInterface() { } + virtual ~SnapshottingProgressReportingInterface() = default; virtual void ProgressStep() = 0; virtual bool ProgressReport(bool force) = 0; }; - // An implementation of V8 heap graph extractor. class V8HeapExplorer : public HeapEntriesAllocator { public: V8HeapExplorer(HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress, v8::HeapProfiler::ObjectNameResolver* resolver); - virtual ~V8HeapExplorer(); - virtual HeapEntry* AllocateEntry(HeapThing ptr); + ~V8HeapExplorer() override = default; + + HeapEntry* AllocateEntry(HeapThing ptr) override; int EstimateObjectsCount(); - bool IterateAndExtractReferences(SnapshotFiller* filler); + bool IterateAndExtractReferences(HeapSnapshotGenerator* generator); void TagGlobalObjects(); void TagCodeObject(Code* code); void TagBuiltinCodeObject(Code* code, const char* name); @@ -377,91 +342,74 @@ class V8HeapExplorer : public HeapEntriesAllocator { const char* GetSystemEntryName(HeapObject* object); - void ExtractLocation(int entry, HeapObject* object); - void ExtractLocationForJSFunction(int entry, JSFunction* func); - void ExtractReferences(int entry, HeapObject* obj); - void ExtractJSGlobalProxyReferences(int entry, JSGlobalProxy* proxy); - void ExtractJSObjectReferences(int entry, JSObject* js_obj); - void ExtractStringReferences(int entry, String* obj); - void ExtractSymbolReferences(int entry, Symbol* symbol); - void ExtractJSCollectionReferences(int entry, JSCollection* collection); - void ExtractJSWeakCollectionReferences(int entry, + void ExtractLocation(HeapEntry* entry, HeapObject* object); + void ExtractLocationForJSFunction(HeapEntry* entry, JSFunction* func); + void ExtractReferences(HeapEntry* entry, HeapObject* obj); + void ExtractJSGlobalProxyReferences(HeapEntry* entry, JSGlobalProxy* proxy); + void ExtractJSObjectReferences(HeapEntry* entry, JSObject* js_obj); + void ExtractStringReferences(HeapEntry* entry, String* obj); + void ExtractSymbolReferences(HeapEntry* entry, Symbol* symbol); + void ExtractJSCollectionReferences(HeapEntry* entry, + JSCollection* collection); + void ExtractJSWeakCollectionReferences(HeapEntry* entry, JSWeakCollection* collection); - void ExtractEphemeronHashTableReferences(int entry, + void ExtractEphemeronHashTableReferences(HeapEntry* entry, EphemeronHashTable* table); - void ExtractContextReferences(int entry, Context* context); - void ExtractMapReferences(int entry, Map* map); - void ExtractSharedFunctionInfoReferences(int entry, + void ExtractContextReferences(HeapEntry* entry, Context* context); + void ExtractMapReferences(HeapEntry* entry, Map* map); + void ExtractSharedFunctionInfoReferences(HeapEntry* entry, SharedFunctionInfo* shared); - void ExtractScriptReferences(int entry, Script* script); - void ExtractAccessorInfoReferences(int entry, AccessorInfo* accessor_info); - void ExtractAccessorPairReferences(int entry, AccessorPair* accessors); - void ExtractCodeReferences(int entry, Code* code); - void ExtractCellReferences(int entry, Cell* cell); - void ExtractFeedbackCellReferences(int entry, FeedbackCell* feedback_cell); - void ExtractPropertyCellReferences(int entry, PropertyCell* cell); - void ExtractAllocationSiteReferences(int entry, AllocationSite* site); + void ExtractScriptReferences(HeapEntry* entry, Script* script); + void ExtractAccessorInfoReferences(HeapEntry* entry, + AccessorInfo* accessor_info); + void ExtractAccessorPairReferences(HeapEntry* entry, AccessorPair* accessors); + void ExtractCodeReferences(HeapEntry* entry, Code* code); + void ExtractCellReferences(HeapEntry* entry, Cell* cell); + void ExtractFeedbackCellReferences(HeapEntry* entry, + FeedbackCell* feedback_cell); + void ExtractPropertyCellReferences(HeapEntry* entry, PropertyCell* cell); + void ExtractAllocationSiteReferences(HeapEntry* entry, AllocationSite* site); void ExtractArrayBoilerplateDescriptionReferences( - int entry, ArrayBoilerplateDescription* value); - void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer); - void ExtractJSPromiseReferences(int entry, JSPromise* promise); - void ExtractJSGeneratorObjectReferences(int entry, + HeapEntry* entry, ArrayBoilerplateDescription* value); + void ExtractJSArrayBufferReferences(HeapEntry* entry, JSArrayBuffer* buffer); + void ExtractJSPromiseReferences(HeapEntry* entry, JSPromise* promise); + void ExtractJSGeneratorObjectReferences(HeapEntry* entry, JSGeneratorObject* generator); - void ExtractFixedArrayReferences(int entry, FixedArray* array); - void ExtractFeedbackVectorReferences(int entry, + void ExtractFixedArrayReferences(HeapEntry* entry, FixedArray* array); + void ExtractFeedbackVectorReferences(HeapEntry* entry, FeedbackVector* feedback_vector); template <typename T> - void ExtractWeakArrayReferences(int header_size, int entry, T* array); - void ExtractPropertyReferences(JSObject* js_obj, int entry); - void ExtractAccessorPairProperty(JSObject* js_obj, int entry, Name* key, + void ExtractWeakArrayReferences(int header_size, HeapEntry* entry, T* array); + void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry); + void ExtractAccessorPairProperty(HeapEntry* entry, Name* key, Object* callback_obj, int field_offset = -1); - void ExtractElementReferences(JSObject* js_obj, int entry); - void ExtractInternalReferences(JSObject* js_obj, int entry); + void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry); + void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry); bool IsEssentialObject(Object* object); bool IsEssentialHiddenReference(Object* parent, int field_offset); - void SetContextReference(HeapObject* parent_obj, - int parent, - String* reference_name, - Object* child, - int field_offset); - void SetNativeBindReference(HeapObject* parent_obj, - int parent, - const char* reference_name, - Object* child); - void SetElementReference(HeapObject* parent_obj, - int parent, - int index, - Object* child); - void SetInternalReference(HeapObject* parent_obj, - int parent, - const char* reference_name, - Object* child, - int field_offset = -1); - void SetInternalReference(HeapObject* parent_obj, - int parent, - int index, - Object* child, + void SetContextReference(HeapEntry* parent_entry, String* reference_name, + Object* child, int field_offset); + void SetNativeBindReference(HeapEntry* parent_entry, + const char* reference_name, Object* child); + void SetElementReference(HeapEntry* parent_entry, int index, Object* child); + void SetInternalReference(HeapEntry* parent_entry, const char* reference_name, + Object* child, int field_offset = -1); + void SetInternalReference(HeapEntry* parent_entry, int index, Object* child, int field_offset = -1); - void SetHiddenReference(HeapObject* parent_obj, int parent, int index, - Object* child, int field_offset); - void SetWeakReference(HeapObject* parent_obj, - int parent, - const char* reference_name, - Object* child_obj, + void SetHiddenReference(HeapObject* parent_obj, HeapEntry* parent_entry, + int index, Object* child, int field_offset); + void SetWeakReference(HeapEntry* parent_entry, const char* reference_name, + Object* child_obj, int field_offset); + void SetWeakReference(HeapEntry* parent_entry, int index, Object* child_obj, int field_offset); - void SetWeakReference(HeapObject* parent_obj, - int parent, - int index, - Object* child_obj, - int field_offset); - void SetPropertyReference(HeapObject* parent_obj, int parent, - Name* reference_name, Object* child, + void SetPropertyReference(HeapEntry* parent_entry, Name* reference_name, + Object* child, const char* name_format_string = nullptr, int field_offset = -1); void SetDataOrAccessorPropertyReference( - PropertyKind kind, JSObject* parent_obj, int parent, Name* reference_name, + PropertyKind kind, HeapEntry* parent_entry, Name* reference_name, Object* child, const char* name_format_string = nullptr, int field_offset = -1); @@ -480,10 +428,10 @@ class V8HeapExplorer : public HeapEntriesAllocator { StringsStorage* names_; HeapObjectsMap* heap_object_map_; SnapshottingProgressReportingInterface* progress_; - SnapshotFiller* filler_; - HeapObjectsSet objects_tags_; - HeapObjectsSet strong_gc_subroot_names_; - HeapObjectsSet user_roots_; + HeapSnapshotGenerator* generator_ = nullptr; + std::unordered_map<JSGlobalObject*, const char*> objects_tags_; + std::unordered_map<Object*, const char*> strong_gc_subroot_names_; + std::unordered_set<JSGlobalObject*> user_roots_; v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_; std::vector<bool> visited_fields_; @@ -505,7 +453,7 @@ class NativeObjectsExplorer { SnapshottingProgressReportingInterface* progress); virtual ~NativeObjectsExplorer(); int EstimateObjectsCount(); - bool IterateAndExtractReferences(SnapshotFiller* filler); + bool IterateAndExtractReferences(HeapSnapshotGenerator* generator); private: void FillRetainedObjects(); @@ -538,7 +486,7 @@ class NativeObjectsExplorer { HeapSnapshot* snapshot_; StringsStorage* names_; bool embedder_queried_; - HeapObjectsSet in_groups_; + std::unordered_set<Object*> in_groups_; std::unordered_map<v8::RetainedObjectInfo*, std::vector<HeapObject*>*, RetainedInfoHasher, RetainedInfoEquals> objects_by_info_; @@ -549,7 +497,7 @@ class NativeObjectsExplorer { std::unique_ptr<HeapEntriesAllocator> native_entries_allocator_; std::unique_ptr<HeapEntriesAllocator> embedder_graph_entries_allocator_; // Used during references extraction. - SnapshotFiller* filler_; + HeapSnapshotGenerator* generator_ = nullptr; v8::HeapProfiler::RetainerEdges edges_; static HeapThing const kNativesRootObject; @@ -559,27 +507,45 @@ class NativeObjectsExplorer { DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer); }; - class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface { public: + // The HeapEntriesMap instance is used to track a mapping between + // real heap objects and their representations in heap snapshots. + using HeapEntriesMap = std::unordered_map<HeapThing, HeapEntry*>; + HeapSnapshotGenerator(HeapSnapshot* snapshot, v8::ActivityControl* control, v8::HeapProfiler::ObjectNameResolver* resolver, Heap* heap); bool GenerateSnapshot(); + HeapEntry* FindEntry(HeapThing ptr) { + auto it = entries_map_.find(ptr); + return it != entries_map_.end() ? it->second : nullptr; + } + + HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { + return entries_map_.emplace(ptr, allocator->AllocateEntry(ptr)) + .first->second; + } + + HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { + HeapEntry* entry = FindEntry(ptr); + return entry != nullptr ? entry : AddEntry(ptr, allocator); + } + private: bool FillReferences(); - void ProgressStep(); - bool ProgressReport(bool force = false); + void ProgressStep() override; + bool ProgressReport(bool force = false) override; void InitProgressCounter(); HeapSnapshot* snapshot_; v8::ActivityControl* control_; V8HeapExplorer v8_heap_explorer_; NativeObjectsExplorer dom_explorer_; - // Mapping from HeapThing pointers to HeapEntry* pointers. - HeapEntriesMap entries_; + // Mapping from HeapThing pointers to HeapEntry indices. + HeapEntriesMap entries_map_; // Used during snapshot generation. int progress_counter_; int progress_total_; diff --git a/deps/v8/src/profiler/sampling-heap-profiler.cc b/deps/v8/src/profiler/sampling-heap-profiler.cc index 48c3f73958..2e07135d85 100644 --- a/deps/v8/src/profiler/sampling-heap-profiler.cc +++ b/deps/v8/src/profiler/sampling-heap-profiler.cc @@ -6,8 +6,10 @@ #include <stdint.h> #include <memory> + #include "src/api-inl.h" #include "src/base/ieee754.h" +#include "src/base/template-utils.h" #include "src/base/utils/random-number-generator.h" #include "src/frames-inl.h" #include "src/heap/heap.h" @@ -61,7 +63,6 @@ SamplingHeapProfiler::SamplingHeapProfiler( heap->isolate()->random_number_generator())), names_(names), profile_root_(nullptr, "(root)", v8::UnboundScript::kNoScriptId, 0), - samples_(), stack_depth_(stack_depth), rate_(rate), flags_(flags) { @@ -75,8 +76,6 @@ SamplingHeapProfiler::SamplingHeapProfiler( SamplingHeapProfiler::~SamplingHeapProfiler() { heap_->RemoveAllocationObserversFromAllSpaces(other_spaces_observer_.get(), new_space_observer_.get()); - - samples_.clear(); } @@ -96,9 +95,9 @@ void SamplingHeapProfiler::SampleObject(Address soon_object, size_t size) { AllocationNode* node = AddStack(); node->allocations_[size]++; - Sample* sample = new Sample(size, node, loc, this); - samples_.emplace(sample); - sample->global.SetWeak(sample, OnWeakCallback, WeakCallbackType::kParameter); + auto sample = base::make_unique<Sample>(size, node, loc, this); + sample->global.SetWeak(sample.get(), OnWeakCallback, + WeakCallbackType::kParameter); #if __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated" @@ -109,6 +108,7 @@ void SamplingHeapProfiler::SampleObject(Address soon_object, size_t size) { #if __clang__ #pragma clang diagnostic pop #endif + samples_.emplace(sample.get(), std::move(sample)); } void SamplingHeapProfiler::OnWeakCallback( @@ -125,17 +125,10 @@ void SamplingHeapProfiler::OnWeakCallback( AllocationNode::FunctionId id = AllocationNode::function_id( node->script_id_, node->script_position_, node->name_); parent->children_.erase(id); - delete node; node = parent; } } - auto it = std::find_if(sample->profiler->samples_.begin(), - sample->profiler->samples_.end(), - [&sample](const std::unique_ptr<Sample>& s) { - return s.get() == sample; - }); - - sample->profiler->samples_.erase(it); + sample->profiler->samples_.erase(sample); // sample is deleted because its unique ptr was erased from samples_. } @@ -147,11 +140,11 @@ SamplingHeapProfiler::AllocationNode::FindOrAddChildNode(const char* name, auto it = children_.find(id); if (it != children_.end()) { DCHECK_EQ(strcmp(it->second->name_, name), 0); - return it->second; + return it->second.get(); } - auto child = new AllocationNode(this, name, script_id, start_position); - children_.insert(std::make_pair(id, child)); - return child; + auto child = + base::make_unique<AllocationNode>(this, name, script_id, start_position); + return children_.emplace(id, std::move(child)).first->second.get(); } SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::AddStack() { @@ -262,19 +255,19 @@ v8::AllocationProfile::Node* SamplingHeapProfiler::TranslateAllocationNode( allocations.push_back(ScaleSample(alloc.first, alloc.second)); } - profile->nodes().push_back(v8::AllocationProfile::Node( - {ToApiHandle<v8::String>( - isolate_->factory()->InternalizeUtf8String(node->name_)), - script_name, node->script_id_, node->script_position_, line, column, - std::vector<v8::AllocationProfile::Node*>(), allocations})); + profile->nodes().push_back(v8::AllocationProfile::Node{ + ToApiHandle<v8::String>( + isolate_->factory()->InternalizeUtf8String(node->name_)), + script_name, node->script_id_, node->script_position_, line, column, + std::vector<v8::AllocationProfile::Node*>(), allocations}); v8::AllocationProfile::Node* current = &profile->nodes().back(); - // The children map may have nodes inserted into it during translation + // The |children_| map may have nodes inserted into it during translation // because the translation may allocate strings on the JS heap that have // the potential to be sampled. That's ok since map iterators are not // invalidated upon std::map insertion. - for (auto it : node->children_) { + for (const auto& it : node->children_) { current->children.push_back( - TranslateAllocationNode(profile, it.second, scripts)); + TranslateAllocationNode(profile, it.second.get(), scripts)); } node->pinned_ = false; return current; @@ -299,6 +292,5 @@ v8::AllocationProfile* SamplingHeapProfiler::GetAllocationProfile() { return profile; } - } // namespace internal } // namespace v8 diff --git a/deps/v8/src/profiler/sampling-heap-profiler.h b/deps/v8/src/profiler/sampling-heap-profiler.h index 46fa405279..072c5eb677 100644 --- a/deps/v8/src/profiler/sampling-heap-profiler.h +++ b/deps/v8/src/profiler/sampling-heap-profiler.h @@ -8,7 +8,7 @@ #include <deque> #include <map> #include <memory> -#include <set> +#include <unordered_map> #include "include/v8-profiler.h" #include "src/heap/heap.h" #include "src/profiler/strings-storage.h" @@ -77,13 +77,7 @@ class SamplingHeapProfiler { : parent_(parent), script_id_(script_id), script_position_(start_position), - name_(name), - pinned_(false) {} - ~AllocationNode() { - for (auto child : children_) { - delete child.second; - } - } + name_(name) {} private: typedef uint64_t FunctionId; @@ -107,12 +101,12 @@ class SamplingHeapProfiler { // TODO(alph): make use of unordered_map's here. Pay attention to // iterator invalidation during TranslateAllocationNode. std::map<size_t, unsigned int> allocations_; - std::map<FunctionId, AllocationNode*> children_; + std::map<FunctionId, std::unique_ptr<AllocationNode>> children_; AllocationNode* const parent_; const int script_id_; const int script_position_; const char* const name_; - bool pinned_; + bool pinned_ = false; friend class SamplingHeapProfiler; @@ -146,7 +140,7 @@ class SamplingHeapProfiler { std::unique_ptr<SamplingAllocationObserver> other_spaces_observer_; StringsStorage* const names_; AllocationNode profile_root_; - std::set<std::unique_ptr<Sample>> samples_; + std::unordered_map<Sample*, std::unique_ptr<Sample>> samples_; const int stack_depth_; const uint64_t rate_; v8::HeapProfiler::SamplingFlags flags_; @@ -166,7 +160,7 @@ class SamplingAllocationObserver : public AllocationObserver { heap_(heap), random_(random), rate_(rate) {} - virtual ~SamplingAllocationObserver() {} + ~SamplingAllocationObserver() override = default; protected: void Step(int bytes_allocated, Address soon_object, size_t size) override { diff --git a/deps/v8/src/profiler/tick-sample.cc b/deps/v8/src/profiler/tick-sample.cc index e3bd1d9c69..69a6bbf778 100644 --- a/deps/v8/src/profiler/tick-sample.cc +++ b/deps/v8/src/profiler/tick-sample.cc @@ -206,7 +206,7 @@ bool TickSample::GetStackSample(Isolate* v8_isolate, RegisterState* regs, // Check whether we interrupted setup/teardown of a stack frame in JS code. // Avoid this check for C++ code, as that would trigger false positives. if (regs->pc && - isolate->heap()->memory_allocator()->code_range()->contains( + isolate->heap()->memory_allocator()->code_range().contains( reinterpret_cast<i::Address>(regs->pc)) && IsNoFrameRegion(reinterpret_cast<i::Address>(regs->pc))) { // The frame is not setup, so it'd be hard to iterate the stack. Bailout. diff --git a/deps/v8/src/profiler/tracing-cpu-profiler.h b/deps/v8/src/profiler/tracing-cpu-profiler.h index d7da209e2e..d5888f54a3 100644 --- a/deps/v8/src/profiler/tracing-cpu-profiler.h +++ b/deps/v8/src/profiler/tracing-cpu-profiler.h @@ -20,7 +20,7 @@ class TracingCpuProfilerImpl final : private v8::TracingController::TraceStateObserver { public: explicit TracingCpuProfilerImpl(Isolate*); - ~TracingCpuProfilerImpl(); + ~TracingCpuProfilerImpl() override; // v8::TracingController::TraceStateObserver void OnTraceEnabled() final; diff --git a/deps/v8/src/profiler/unbound-queue.h b/deps/v8/src/profiler/unbound-queue.h index 0efe95abdf..547ac191b3 100644 --- a/deps/v8/src/profiler/unbound-queue.h +++ b/deps/v8/src/profiler/unbound-queue.h @@ -18,8 +18,8 @@ namespace internal { // elements, so producer never blocks. Implemented after Herb // Sutter's article: // http://www.ddj.com/high-performance-computing/210604448 -template<typename Record> -class UnboundQueue BASE_EMBEDDED { +template <typename Record> +class UnboundQueue { public: inline UnboundQueue(); inline ~UnboundQueue(); |