diff --git a/src/profiler/heap-snapshot-generator-inl.h b/src/profiler/heap-snapshot-generator-inl.h index edf6559706..6ddb6d4658 100644 --- a/src/profiler/heap-snapshot-generator-inl.h +++ b/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(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::deque::iterator HeapEntry::children_begin() { - DCHECK_GE(children_index_, 0); - SLOW_DCHECK( - children_index_ < static_cast(snapshot_->children().size()) || - (children_index_ == static_cast(snapshot_->children().size()) && - children_count_ == 0)); - return snapshot_->children().begin() + children_index_; +std::vector::iterator HeapEntry::children_begin() const { + return index_ == 0 ? snapshot_->children().begin() + : snapshot_->entries()[index_ - 1].children_end(); } -std::deque::iterator HeapEntry::children_end() { - return children_begin() + children_count_; +std::vector::iterator HeapEntry::children_end() const { + DCHECK_GE(children_end_index_, 0); + return snapshot_->children().begin() + children_end_index_; +} + +int HeapEntry::children_count() const { + return static_cast(children_end() - children_begin()); } Isolate* HeapEntry::isolate() const { return snapshot_->profiler()->isolate(); } diff --git a/src/profiler/heap-snapshot-generator.cc b/src/profiler/heap-snapshot-generator.cc index a98c60556d..444575b00d 100644 --- a/src/profiler/heap-snapshot-generator.cc +++ b/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,56 +46,43 @@ 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::Print( const char* prefix, const char* edge_name, int max_depth, int indent) { STATIC_ASSERT(sizeof(unsigned) == sizeof(id())); @@ -176,34 +164,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(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 +193,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; + root_entry_ = AddEntry(HeapEntry::kSynthetic, "", + HeapObjectsMap::kInternalRootObjectId, 0, 0); + DCHECK_EQ(1u, entries_.size()); + DCHECK_EQ(root_entry_, &entries_.front()); } - -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; +void HeapSnapshot::AddGcRootsEntry() { + DCHECK_NULL(gc_roots_entry_); + gc_roots_entry_ = AddEntry(HeapEntry::kSynthetic, "(GC roots)", + HeapObjectsMap::kGcRootsObjectId, 0, 0); } -HeapEntry* HeapSnapshot::AddGcSubrootEntry(Root root, SnapshotObjectId id) { - DCHECK_EQ(gc_subroot_indexes_[static_cast(root)], HeapEntry::kNoEntry); - HeapEntry* entry = +void HeapSnapshot::AddGcSubrootEntry(Root root, SnapshotObjectId id) { + DCHECK_NULL(gc_subroot_entries_[static_cast(root)]); + gc_subroot_entries_[static_cast(root)] = AddEntry(HeapEntry::kSynthetic, RootVisitor::RootName(root), id, 0, 0); - gc_subroot_indexes_[static_cast(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 +224,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(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(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* 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* 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) { @@ -555,7 +504,7 @@ HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) { return AddEntry(reinterpret_cast(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); @@ -573,7 +522,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(); @@ -676,25 +626,20 @@ HeapEntry* V8HeapExplorer::AddEntry(Address address, return snapshot_->AddEntry(type, name, object_id, size, trace_node_id); } - class SnapshotFiller { public: SnapshotFiller(HeapSnapshot* snapshot, HeapSnapshotGenerator::HeapEntriesMap* entries_map) - : snapshot_(snapshot), - names_(snapshot->profiler()->names()), - entries_map_(entries_map) {} + : names_(snapshot->profiler()->names()), entries_map_(entries_map) {} HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { - HeapEntry* entry = allocator->AllocateEntry(ptr); - entries_map_->emplace(ptr, entry->index()); - return entry; + return entries_map_->emplace(ptr, allocator->AllocateEntry(ptr)) + .first->second; } HeapEntry* FindEntry(HeapThing ptr) { auto it = entries_map_->find(ptr); - return it != entries_map_->end() ? &snapshot_->entries()[it->second] - : nullptr; + return it != entries_map_->end() ? it->second : nullptr; } HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { @@ -702,43 +647,32 @@ class SnapshotFiller { 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 SetIndexedReference(HeapGraphEdge::Type type, HeapEntry* parent, + int index, HeapEntry* child) { + parent->SetIndexedReference(type, index, child); } - 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 SetIndexedAutoIndexReference(HeapGraphEdge::Type type, HeapEntry* parent, + HeapEntry* child) { + int index = parent->children_count_build_phase() + 1; + parent->SetIndexedReference(type, index, child); } - 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 SetNamedReference(HeapGraphEdge::Type type, HeapEntry* parent, + const char* reference_name, HeapEntry* child) { + parent->SetNamedReference(type, reference_name, child); } - 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; + void SetNamedAutoIndexReference(HeapGraphEdge::Type type, HeapEntry* parent, + const char* description, HeapEntry* child) { + int index = parent->children_count_build_phase() + 1; const char* name = description ? names_->GetFormatted("%d / %s", index, description) : names_->GetName(index); - parent_entry->SetNamedReference(type, name, child_entry); + parent->SetNamedReference(type, name, child); } private: - HeapSnapshot* snapshot_; StringsStorage* names_; HeapSnapshotGenerator::HeapEntriesMap* entries_map_; }; @@ -778,7 +712,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)), @@ -817,10 +751,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()) { @@ -884,17 +818,15 @@ void V8HeapExplorer::ExtractReferences(int entry, HeapObject* obj) { } } - -void V8HeapExplorer::ExtractJSGlobalProxyReferences( - int entry, JSGlobalProxy* proxy) { +void V8HeapExplorer::ExtractJSGlobalProxyReferences(HeapEntry* entry, + JSGlobalProxy* proxy) { SetInternalReference(proxy, 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); @@ -977,8 +909,7 @@ void V8HeapExplorer::ExtractJSObjectReferences( 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(), @@ -996,28 +927,26 @@ void V8HeapExplorer::ExtractStringReferences(int entry, String* string) { } } - -void V8HeapExplorer::ExtractSymbolReferences(int entry, Symbol* symbol) { +void V8HeapExplorer::ExtractSymbolReferences(HeapEntry* entry, Symbol* symbol) { SetInternalReference(symbol, entry, "name", symbol->name(), Symbol::kNameOffset); } - -void V8HeapExplorer::ExtractJSCollectionReferences(int entry, +void V8HeapExplorer::ExtractJSCollectionReferences(HeapEntry* entry, JSCollection* collection) { SetInternalReference(collection, entry, "table", collection->table(), JSCollection::kTableOffset); } -void V8HeapExplorer::ExtractJSWeakCollectionReferences(int entry, +void V8HeapExplorer::ExtractJSWeakCollectionReferences(HeapEntry* entry, JSWeakCollection* obj) { SetInternalReference(obj, 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; @@ -1029,13 +958,12 @@ void V8HeapExplorer::ExtractEphemeronHashTableReferences( SetWeakReference(table, 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); + filler_->SetNamedAutoIndexReference(HeapGraphEdge::kInternal, key_entry, + edge_name, value_entry); } } } @@ -1043,20 +971,17 @@ void V8HeapExplorer::ExtractEphemeronHashTableReferences( // 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 int native_context_indices[] = { -#define CONTEXT_FIELD_INDEX(index, ...) Context::index, - NATIVE_CONTEXT_FIELDS(CONTEXT_FIELD_INDEX) +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 }; -static const char* native_context_names[] = { -#define CONTEXT_FIELD_NAME(index, _, name) #name, - NATIVE_CONTEXT_FIELDS(CONTEXT_FIELD_NAME) -#undef CONTEXT_FIELD_NAME -}; -STATIC_ASSERT(arraysize(native_context_indices) == - arraysize(native_context_names)); -void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) { +void V8HeapExplorer::ExtractContextReferences(HeapEntry* entry, + Context* context) { if (!context->IsNativeContext() && context->is_declaration_context()) { ScopeInfo* scope_info = context->scope_info(); // Add context allocated locals. @@ -1094,9 +1019,9 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) { if (context->IsNativeContext()) { TagObject(context->normalized_map_cache(), "(context norm. map cache)"); TagObject(context->embedder_data(), "(context data)"); - for (size_t i = 0; i < arraysize(native_context_indices); i++) { - int index = native_context_indices[i]; - const char* name = native_context_names[i]; + 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(context, entry, name, context->get(index), FixedArray::OffsetOfElementAt(index)); } @@ -1117,7 +1042,7 @@ 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->GetHeapObjectIfWeak( @@ -1181,9 +1106,8 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { Map::kDependentCodeOffset); } - void V8HeapExplorer::ExtractSharedFunctionInfoReferences( - int entry, SharedFunctionInfo* shared) { + HeapEntry* entry, SharedFunctionInfo* shared) { HeapObject* obj = shared; String* shared_name = shared->DebugName(); const char* name = nullptr; @@ -1214,7 +1138,7 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences( SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset); } -void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) { +void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) { HeapObject* obj = script; SetInternalReference(obj, entry, "source", script->source(), @@ -1231,9 +1155,8 @@ void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) { Script::kLineEndsOffset); } - void V8HeapExplorer::ExtractAccessorInfoReferences( - int entry, AccessorInfo* accessor_info) { + HeapEntry* entry, AccessorInfo* accessor_info) { SetInternalReference(accessor_info, entry, "name", accessor_info->name(), AccessorInfo::kNameOffset); SetInternalReference(accessor_info, entry, "expected_receiver_type", @@ -1247,8 +1170,8 @@ void V8HeapExplorer::ExtractAccessorInfoReferences( AccessorInfo::kDataOffset); } -void V8HeapExplorer::ExtractAccessorPairReferences( - int entry, AccessorPair* accessors) { +void V8HeapExplorer::ExtractAccessorPairReferences(HeapEntry* entry, + AccessorPair* accessors) { SetInternalReference(accessors, entry, "getter", accessors->getter(), AccessorPair::kGetterOffset); SetInternalReference(accessors, entry, "setter", accessors->setter(), @@ -1267,7 +1190,7 @@ 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, @@ -1283,18 +1206,18 @@ void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) { Code::kSourcePositionTableOffset); } -void V8HeapExplorer::ExtractCellReferences(int entry, Cell* cell) { +void V8HeapExplorer::ExtractCellReferences(HeapEntry* entry, Cell* cell) { SetInternalReference(cell, 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(), FeedbackCell::kValueOffset); } -void V8HeapExplorer::ExtractPropertyCellReferences(int entry, +void V8HeapExplorer::ExtractPropertyCellReferences(HeapEntry* entry, PropertyCell* cell) { SetInternalReference(cell, entry, "value", cell->value(), PropertyCell::kValueOffset); @@ -1303,7 +1226,7 @@ void V8HeapExplorer::ExtractPropertyCellReferences(int entry, PropertyCell::kDependentCodeOffset); } -void V8HeapExplorer::ExtractAllocationSiteReferences(int entry, +void V8HeapExplorer::ExtractAllocationSiteReferences(HeapEntry* entry, AllocationSite* site) { SetInternalReference(site, entry, "transition_info", site->transition_info_or_boilerplate(), @@ -1316,7 +1239,7 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(int entry, } void V8HeapExplorer::ExtractArrayBoilerplateDescriptionReferences( - int entry, ArrayBoilerplateDescription* value) { + HeapEntry* entry, ArrayBoilerplateDescription* value) { SetInternalReference(value, entry, "constant_elements", value->constant_elements(), ArrayBoilerplateDescription::kConstantElementsOffset); @@ -1338,8 +1261,8 @@ 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; @@ -1351,14 +1274,15 @@ void V8HeapExplorer::ExtractJSArrayBufferReferences( entry, "backing_store", data_entry); } -void V8HeapExplorer::ExtractJSPromiseReferences(int entry, JSPromise* promise) { +void V8HeapExplorer::ExtractJSPromiseReferences(HeapEntry* entry, + JSPromise* promise) { SetInternalReference(promise, entry, "reactions_or_result", promise->reactions_or_result(), JSPromise::kReactionsOrResultOffset); } void V8HeapExplorer::ExtractJSGeneratorObjectReferences( - int entry, JSGeneratorObject* generator) { + HeapEntry* entry, JSGeneratorObject* generator) { SetInternalReference(generator, entry, "function", generator->function(), JSGeneratorObject::kFunctionOffset); SetInternalReference(generator, entry, "context", generator->context(), @@ -1370,7 +1294,8 @@ void V8HeapExplorer::ExtractJSGeneratorObjectReferences( 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), @@ -1379,7 +1304,7 @@ void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) { } 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->GetHeapObjectIfWeak(&code_heap_object)) { @@ -1389,8 +1314,8 @@ void V8HeapExplorer::ExtractFeedbackVectorReferences( } template -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; @@ -1404,7 +1329,8 @@ void V8HeapExplorer::ExtractWeakArrayReferences(int header_size, int entry, } } -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(); @@ -1465,9 +1391,8 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) { } } - -void V8HeapExplorer::ExtractAccessorPairProperty(JSObject* js_obj, int entry, - Name* key, +void V8HeapExplorer::ExtractAccessorPairProperty(JSObject* js_obj, + HeapEntry* entry, Name* key, Object* callback_obj, int field_offset) { if (!callback_obj->IsAccessorPair()) return; @@ -1483,8 +1408,8 @@ void V8HeapExplorer::ExtractAccessorPairProperty(JSObject* js_obj, int entry, } } - -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()); @@ -1510,8 +1435,8 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) { } } - -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); @@ -1606,8 +1531,7 @@ 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); // Extract unvisited fields as hidden references and restore tags @@ -1661,11 +1585,10 @@ bool V8HeapExplorer::IsEssentialHiddenReference(Object* parent, } void V8HeapExplorer::SetContextReference(HeapObject* parent_obj, - int parent_entry, + 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) { + DCHECK_EQ(parent_entry, GetEntry(parent_obj)); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; filler_->SetNamedReference(HeapGraphEdge::kContextVariable, parent_entry, @@ -1680,37 +1603,32 @@ void V8HeapExplorer::MarkVisitedField(int offset) { visited_fields_[index] = true; } - void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj, - int parent_entry, + HeapEntry* parent_entry, const char* reference_name, Object* child_obj) { - DCHECK(parent_entry == GetEntry(parent_obj)->index()); + DCHECK_EQ(parent_entry, GetEntry(parent_obj)); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; filler_->SetNamedReference(HeapGraphEdge::kShortcut, parent_entry, reference_name, child_entry); } - void V8HeapExplorer::SetElementReference(HeapObject* parent_obj, - int parent_entry, - int index, + HeapEntry* parent_entry, int index, Object* child_obj) { - DCHECK(parent_entry == GetEntry(parent_obj)->index()); + DCHECK_EQ(parent_entry, GetEntry(parent_obj)); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; filler_->SetIndexedReference(HeapGraphEdge::kElement, parent_entry, index, child_entry); } - void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, - int parent_entry, + 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) { + DCHECK_EQ(parent_entry, GetEntry(parent_obj)); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; if (IsEssentialObject(child_obj)) { @@ -1722,13 +1640,10 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, 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()); + HeapEntry* parent_entry, int index, + Object* child_obj, int field_offset) { + DCHECK_EQ(parent_entry, GetEntry(parent_obj)); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; if (IsEssentialObject(child_obj)) { @@ -1741,9 +1656,9 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, } 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)) { @@ -1752,13 +1667,11 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, } } - void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, - int parent_entry, + 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) { + DCHECK_EQ(parent_entry, GetEntry(parent_obj)); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; if (IsEssentialObject(child_obj)) { @@ -1770,13 +1683,10 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, 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()); + HeapEntry* parent_entry, int index, + Object* child_obj, int field_offset) { + DCHECK_EQ(parent_entry, GetEntry(parent_obj)); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; if (IsEssentialObject(child_obj)) { @@ -1789,9 +1699,10 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, } void V8HeapExplorer::SetDataOrAccessorPropertyReference( - PropertyKind kind, JSObject* parent_obj, int parent_entry, + PropertyKind kind, JSObject* parent_obj, HeapEntry* parent_entry, Name* reference_name, Object* child_obj, const char* name_format_string, int field_offset) { + DCHECK_EQ(parent_entry, GetEntry(parent_obj)); if (kind == kAccessor) { ExtractAccessorPairProperty(parent_obj, parent_entry, reference_name, child_obj, field_offset); @@ -1801,14 +1712,10 @@ void V8HeapExplorer::SetDataOrAccessorPropertyReference( } } - -void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, - int parent_entry, - Name* reference_name, - Object* child_obj, - const char* name_format_string, - int field_offset) { - DCHECK(parent_entry == GetEntry(parent_obj)->index()); +void V8HeapExplorer::SetPropertyReference( + HeapObject* parent_obj, HeapEntry* parent_entry, Name* reference_name, + Object* child_obj, const char* name_format_string, int field_offset) { + DCHECK_EQ(parent_entry, GetEntry(parent_obj)); HeapEntry* child_entry = GetEntry(child_obj); if (child_entry == nullptr) return; HeapGraphEdge::Type type = @@ -1830,22 +1737,19 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, void V8HeapExplorer::SetRootGcRootsReference() { filler_->SetIndexedAutoIndexReference( - HeapGraphEdge::kElement, - snapshot_->root()->index(), - snapshot_->gc_roots()); + HeapGraphEdge::kElement, snapshot_->root(), 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(), nullptr, child_entry); } void V8HeapExplorer::SetGcRootsReference(Root root) { filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, - snapshot_->gc_roots()->index(), + snapshot_->gc_roots(), snapshot_->gc_subroot(root)); } @@ -1857,11 +1761,10 @@ 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); + filler_->SetNamedReference(edge_type, snapshot_->gc_subroot(root), name, + child_entry); } else { - filler_->SetNamedAutoIndexReference(edge_type, - snapshot_->gc_subroot(root)->index(), + filler_->SetNamedAutoIndexReference(edge_type, snapshot_->gc_subroot(root), description, child_entry); } @@ -2206,10 +2109,9 @@ void NativeObjectsExplorer::FillEdges() { Handle parent_object = v8::Utils::OpenHandle( *pair.first->Get(reinterpret_cast(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 = + filler_->FindOrAddEntry(parent, native_entries_allocator_.get()); + DCHECK_NOT_NULL(parent_entry); Handle child_object = v8::Utils::OpenHandle( *pair.second->Get(reinterpret_cast(isolate_))); HeapObject* child = HeapObject::cast(*child_object); @@ -2262,7 +2164,7 @@ bool NativeObjectsExplorer::IterateAndExtractReferences( for (const auto& node : graph.nodes()) { if (node->IsRootNode()) { filler_->SetIndexedAutoIndexReference( - HeapGraphEdge::kElement, snapshot_->root()->index(), + HeapGraphEdge::kElement, snapshot_->root(), EntryForEmbedderGraphNode(node.get())); } // Adjust the name and the type of the V8 wrapper node. @@ -2281,17 +2183,14 @@ bool NativeObjectsExplorer::IterateAndExtractReferences( // The |from| and |to| can nullptr if the corrsponding 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); + filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, from, + to); } else { - filler_->SetNamedReference(HeapGraphEdge::kInternal, from_index, - edge.name, to); + filler_->SetNamedReference(HeapGraphEdge::kInternal, from, edge.name, + to); } } } @@ -2332,11 +2231,8 @@ void NativeObjectsExplorer::SetNativeRootReference( 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); + filler_->SetNamedAutoIndexReference(HeapGraphEdge::kInternal, group_entry, + nullptr, child_entry); } @@ -2347,12 +2243,9 @@ void NativeObjectsExplorer::SetWrapperNativeReferences( HeapEntry* info_entry = filler_->FindOrAddEntry(info, native_entries_allocator_.get()); DCHECK_NOT_NULL(info_entry); - filler_->SetNamedReference(HeapGraphEdge::kInternal, - wrapper_entry->index(), - "native", + filler_->SetNamedReference(HeapGraphEdge::kInternal, wrapper_entry, "native", info_entry); - filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, - info_entry->index(), + filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, info_entry, wrapper_entry); } @@ -2363,10 +2256,8 @@ void NativeObjectsExplorer::SetRootNativeRootsReference() { HeapEntry* group_entry = filler_->FindOrAddEntry(group_info, native_entries_allocator_.get()); DCHECK_NOT_NULL(group_entry); - filler_->SetIndexedAutoIndexReference( - HeapGraphEdge::kElement, - snapshot_->root()->index(), - group_entry); + filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, + snapshot_->root(), group_entry); } } @@ -2713,9 +2604,8 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge, writer_->AddString(buffer.start()); } - void HeapSnapshotJSONSerializer::SerializeEdges() { - std::deque& edges = snapshot_->children(); + std::vector& edges = snapshot_->children(); for (size_t i = 0; i < edges.size(); ++i) { DCHECK(i == 0 || edges[i - 1]->from()->index() <= edges[i]->from()->index()); @@ -2751,16 +2641,14 @@ void HeapSnapshotJSONSerializer::SerializeNode(const HeapEntry* entry) { writer_->AddString(buffer.start()); } - void HeapSnapshotJSONSerializer::SerializeNodes() { - std::vector& entries = snapshot_->entries(); + const std::deque& 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/src/profiler/heap-snapshot-generator.h b/src/profiler/heap-snapshot-generator.h index 61ca21e6f4..e62bb0ed4b 100644 --- a/src/profiler/heap-snapshot-generator.h +++ b/src/profiler/heap-snapshot-generator.h @@ -60,9 +60,8 @@ class HeapGraphEdge { 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 { @@ -86,12 +85,7 @@ class HeapGraphEdge { class TypeField : public BitField {}; class FromIndexField : public BitField {}; 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_; @@ -119,15 +113,9 @@ class HeapEntry { kSymbol = v8::HeapGraphNode::kSymbol, kBigInt = v8::HeapGraphNode::kBigInt }; - static const int kNoEntry; - HeapEntry() = default; - 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_); } @@ -137,8 +125,9 @@ class HeapEntry { 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_; } + int children_count_build_phase() const { return children_count_; } + 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); @@ -153,13 +142,18 @@ class HeapEntry { const char* prefix, const char* edge_name, int max_depth, int indent); private: - V8_INLINE std::deque::iterator children_begin(); - V8_INLINE std::deque::iterator children_end(); + V8_INLINE std::vector::iterator children_begin() const; + V8_INLINE std::vector::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_; @@ -168,7 +162,6 @@ class HeapEntry { 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 @@ -179,22 +172,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(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(root)]; } - std::vector& entries() { return entries_; } + std::deque& entries() { return entries_; } std::deque& edges() { return edges_; } - std::deque& children() { return children_; } + std::vector& children() { return children_; } const std::vector& 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, @@ -202,28 +196,28 @@ class HeapSnapshot { unsigned trace_node_id); void AddSyntheticRootEntries(); HeapEntry* GetEntryById(SnapshotObjectId id); - std::vector* 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(Root::kNumberOfRoots)]; - std::vector entries_; + HeapEntry* root_entry_ = nullptr; + HeapEntry* gc_roots_entry_ = nullptr; + HeapEntry* gc_subroot_entries_[static_cast(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 entries_; std::deque edges_; - std::deque children_; - std::vector sorted_entries_; + std::vector children_; + std::unordered_map entries_by_id_cache_; std::vector locations_; - SnapshotObjectId max_snapshot_js_object_id_; - - friend class HeapSnapshotTester; + SnapshotObjectId max_snapshot_js_object_id_ = -1; DISALLOW_COPY_AND_ASSIGN(HeapSnapshot); }; @@ -341,93 +335,81 @@ 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 - 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, - Object* callback_obj, int field_offset = -1); - void ExtractElementReferences(JSObject* js_obj, int entry); - void ExtractInternalReferences(JSObject* js_obj, int entry); + void ExtractWeakArrayReferences(int header_size, HeapEntry* entry, T* array); + void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry); + void ExtractAccessorPairProperty(JSObject* js_obj, HeapEntry* entry, + Name* key, Object* callback_obj, + int field_offset = -1); + 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, + void SetContextReference(HeapObject* parent_obj, HeapEntry* parent_entry, + 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, + void SetNativeBindReference(HeapObject* parent_obj, HeapEntry* parent_entry, + const char* reference_name, Object* child); + void SetElementReference(HeapObject* parent_obj, HeapEntry* parent_entry, + int index, Object* child); + void SetInternalReference(HeapObject* parent_obj, HeapEntry* parent_entry, + const char* reference_name, Object* child, int field_offset = -1); - void SetInternalReference(HeapObject* parent_obj, - int parent, - 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 SetInternalReference(HeapObject* parent_obj, HeapEntry* parent_entry, + int index, Object* child, int field_offset = -1); + void SetHiddenReference(HeapObject* parent_obj, HeapEntry* parent_entry, + int index, Object* child, int field_offset); + void SetWeakReference(HeapObject* parent_obj, HeapEntry* parent_entry, + const char* reference_name, 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, + void SetWeakReference(HeapObject* parent_obj, HeapEntry* parent_entry, + int index, Object* child_obj, int field_offset); + void SetPropertyReference(HeapObject* parent_obj, 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, - Object* child, const char* name_format_string = nullptr, - int field_offset = -1); + PropertyKind kind, JSObject* parent_obj, HeapEntry* parent_entry, + Name* reference_name, Object* child, + const char* name_format_string = nullptr, int field_offset = -1); void SetUserGlobalReference(Object* user_global); void SetRootGcRootsReference(); @@ -528,7 +510,7 @@ 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; + using HeapEntriesMap = std::unordered_map; HeapSnapshotGenerator(HeapSnapshot* snapshot, v8::ActivityControl* control, diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc index fe44bb7410..257ef1c723 100644 --- a/test/cctest/test-heap-profiler.cc +++ b/test/cctest/test-heap-profiler.cc @@ -157,12 +157,9 @@ static Optional GetLocation(const v8::HeapSnapshot* s, const v8::HeapGraphNode* node) { const i::HeapSnapshot* snapshot = reinterpret_cast(s); const std::vector& locations = snapshot->locations(); - const int index = - const_cast(reinterpret_cast(node)) - ->index(); - + const i::HeapEntry* entry = reinterpret_cast(node); for (const auto& loc : locations) { - if (loc.entry_index == index) { + if (loc.entry_index == entry->index()) { return Optional(loc); } } @@ -223,7 +220,7 @@ static bool ValidateSnapshot(const v8::HeapSnapshot* snapshot, int depth = 3) { entry->value = reinterpret_cast(ref_count + 1); } uint32_t unretained_entries_count = 0; - std::vector& entries = heap_snapshot->entries(); + std::deque& entries = heap_snapshot->entries(); for (i::HeapEntry& entry : entries) { v8::base::HashMap::Entry* map_entry = visited.Lookup( reinterpret_cast(&entry), @@ -1000,21 +997,6 @@ TEST(HeapEntryIdsAndGC) { CHECK_EQ(b1->GetId(), b2->GetId()); } - -TEST(HeapSnapshotRootPreservedAfterSorting) { - LocalContext env; - v8::HandleScope scope(env->GetIsolate()); - v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); - const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); - CHECK(ValidateSnapshot(snapshot)); - const v8::HeapGraphNode* root1 = snapshot->GetRoot(); - const_cast(reinterpret_cast( - snapshot))->GetSortedEntriesList(); - const v8::HeapGraphNode* root2 = snapshot->GetRoot(); - CHECK_EQ(root1, root2); -} - - namespace { class TestJSONStream : public v8::OutputStream {