[heap profiler] Refactor: Replace indices with HeapEntry*

Change-Id: I0c176f66711d45e2f59d527f3133a1afbf825ec3
Reviewed-on: https://chromium-review.googlesource.com/1229613
Commit-Queue: Alexei Filippov <alph@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56245}
This commit is contained in:
Alexei Filippov 2018-09-26 10:40:33 -07:00 committed by Commit Bot
parent c86b90d12c
commit 69a502ce5c
4 changed files with 281 additions and 438 deletions

View File

@ -13,51 +13,41 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
HeapEntry* HeapGraphEdge::from() const { HeapEntry* HeapGraphEdge::from() const {
return &snapshot()->entries()[from_index()]; return &snapshot()->entries()[from_index()];
} }
Isolate* HeapGraphEdge::isolate() const { return to_entry_->isolate(); }
Isolate* HeapGraphEdge::isolate() const {
return snapshot()->profiler()->isolate();
}
HeapSnapshot* HeapGraphEdge::snapshot() const { HeapSnapshot* HeapGraphEdge::snapshot() const {
return to_entry_->snapshot(); return to_entry_->snapshot();
} }
int HeapEntry::index() const {
return static_cast<int>(this - &snapshot_->entries().front());
}
int HeapEntry::set_children_index(int index) { 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_; int next_index = index + children_count_;
children_count_ = 0; children_end_index_ = index;
return next_index; return next_index;
} }
void HeapEntry::add_child(HeapGraphEdge* edge) { 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<HeapGraphEdge*>::iterator HeapEntry::children_begin() { std::vector<HeapGraphEdge*>::iterator HeapEntry::children_begin() const {
DCHECK_GE(children_index_, 0); return index_ == 0 ? snapshot_->children().begin()
SLOW_DCHECK( : snapshot_->entries()[index_ - 1].children_end();
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::deque<HeapGraphEdge*>::iterator HeapEntry::children_end() { std::vector<HeapGraphEdge*>::iterator HeapEntry::children_end() const {
return children_begin() + children_count_; DCHECK_GE(children_end_index_, 0);
return snapshot_->children().begin() + children_end_index_;
}
int HeapEntry::children_count() const {
return static_cast<int>(children_end() - children_begin());
} }
Isolate* HeapEntry::isolate() const { return snapshot_->profiler()->isolate(); } Isolate* HeapEntry::isolate() const { return snapshot_->profiler()->isolate(); }

View File

@ -33,10 +33,11 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
HeapGraphEdge::HeapGraphEdge(Type type, const char* name, HeapEntry* from,
HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to) HeapEntry* to)
: bit_field_(TypeField::encode(type) | FromIndexField::encode(from)), : bit_field_(TypeField::encode(type) |
to_index_(to), FromIndexField::encode(from->index())),
to_entry_(to),
name_(name) { name_(name) {
DCHECK(type == kContextVariable DCHECK(type == kContextVariable
|| type == kProperty || type == kProperty
@ -45,56 +46,42 @@ HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to)
|| type == kWeak); || type == kWeak);
} }
HeapGraphEdge::HeapGraphEdge(Type type, int index, HeapEntry* from,
HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to) HeapEntry* to)
: bit_field_(TypeField::encode(type) | FromIndexField::encode(from)), : bit_field_(TypeField::encode(type) |
to_index_(to), FromIndexField::encode(from->index())),
to_entry_(to),
index_(index) { index_(index) {
DCHECK(type == kElement || type == kHidden); DCHECK(type == kElement || type == kHidden);
} }
HeapEntry::HeapEntry(HeapSnapshot* snapshot, int index, Type type,
void HeapGraphEdge::ReplaceToIndexWithEntry(HeapSnapshot* snapshot) { const char* name, SnapshotObjectId id, size_t self_size,
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,
unsigned trace_node_id) unsigned trace_node_id)
: type_(type), : type_(type),
children_count_(0), index_(index),
children_index_(-1),
self_size_(self_size), self_size_(self_size),
snapshot_(snapshot), snapshot_(snapshot),
name_(name), name_(name),
id_(id), id_(id),
trace_node_id_(trace_node_id) { } trace_node_id_(trace_node_id) {
DCHECK_GE(index, 0);
}
void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
const char* name, const char* name,
HeapEntry* entry) { HeapEntry* entry) {
HeapGraphEdge edge(type, name, this->index(), entry->index());
snapshot_->edges().push_back(edge);
++children_count_; ++children_count_;
snapshot_->edges().emplace_back(type, name, this, entry);
} }
void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
int index, int index,
HeapEntry* entry) { HeapEntry* entry) {
HeapGraphEdge edge(type, index, this->index(), entry->index());
snapshot_->edges().push_back(edge);
++children_count_; ++children_count_;
snapshot_->edges().emplace_back(type, index, this, entry);
} }
void HeapEntry::Print( void HeapEntry::Print(
const char* prefix, const char* edge_name, int max_depth, int indent) { const char* prefix, const char* edge_name, int max_depth, int indent) {
STATIC_ASSERT(sizeof(unsigned) == sizeof(id())); STATIC_ASSERT(sizeof(unsigned) == sizeof(id()));
@ -176,34 +163,24 @@ const char* HeapEntry::TypeAsString() {
} }
} }
HeapSnapshot::HeapSnapshot(HeapProfiler* profiler) : profiler_(profiler) {
HeapSnapshot::HeapSnapshot(HeapProfiler* profiler)
: profiler_(profiler),
root_index_(HeapEntry::kNoEntry),
gc_roots_index_(HeapEntry::kNoEntry),
max_snapshot_js_object_id_(0) {
// It is very important to keep objects that form a heap snapshot // It is very important to keep objects that form a heap snapshot
// as small as possible. Check assumptions about data structure sizes. // as small as possible. Check assumptions about data structure sizes.
STATIC_ASSERT(((kPointerSize == 4) && (sizeof(HeapGraphEdge) == 12)) || STATIC_ASSERT((kPointerSize == 4 && sizeof(HeapGraphEdge) == 12) ||
((kPointerSize == 8) && (sizeof(HeapGraphEdge) == 24))); (kPointerSize == 8 && sizeof(HeapGraphEdge) == 24));
STATIC_ASSERT(((kPointerSize == 4) && (sizeof(HeapEntry) == 28)) || STATIC_ASSERT((kPointerSize == 4 && sizeof(HeapEntry) == 28) ||
((kPointerSize == 8) && (sizeof(HeapEntry) == 40))); (kPointerSize == 8 && sizeof(HeapEntry) == 40));
for (int i = 0; i < static_cast<int>(Root::kNumberOfRoots); ++i) { memset(&gc_subroot_entries_, 0, sizeof(gc_subroot_entries_));
gc_subroot_indexes_[i] = HeapEntry::kNoEntry;
}
} }
void HeapSnapshot::Delete() { void HeapSnapshot::Delete() {
profiler_->RemoveSnapshot(this); profiler_->RemoveSnapshot(this);
} }
void HeapSnapshot::RememberLastJSObjectId() { void HeapSnapshot::RememberLastJSObjectId() {
max_snapshot_js_object_id_ = profiler_->heap_object_map()->last_assigned_id(); max_snapshot_js_object_id_ = profiler_->heap_object_map()->last_assigned_id();
} }
void HeapSnapshot::AddSyntheticRootEntries() { void HeapSnapshot::AddSyntheticRootEntries() {
AddRootEntry(); AddRootEntry();
AddGcRootsEntry(); AddGcRootsEntry();
@ -215,42 +192,30 @@ void HeapSnapshot::AddSyntheticRootEntries() {
DCHECK_EQ(HeapObjectsMap::kFirstAvailableObjectId, id); DCHECK_EQ(HeapObjectsMap::kFirstAvailableObjectId, id);
} }
void HeapSnapshot::AddRootEntry() {
HeapEntry* HeapSnapshot::AddRootEntry() { DCHECK_NULL(root_entry_);
DCHECK_EQ(root_index_, HeapEntry::kNoEntry);
DCHECK(entries_.empty()); // Root entry must be the first one. DCHECK(entries_.empty()); // Root entry must be the first one.
HeapEntry* entry = AddEntry(HeapEntry::kSynthetic, root_entry_ = AddEntry(HeapEntry::kSynthetic, "",
"", HeapObjectsMap::kInternalRootObjectId, 0, 0);
HeapObjectsMap::kInternalRootObjectId, DCHECK_EQ(1u, entries_.size());
0, DCHECK_EQ(root_entry_, &entries_.front());
0);
root_index_ = entry->index();
DCHECK_EQ(root_index_, 0);
return entry;
} }
void HeapSnapshot::AddGcRootsEntry() {
HeapEntry* HeapSnapshot::AddGcRootsEntry() { DCHECK_NULL(gc_roots_entry_);
DCHECK_EQ(gc_roots_index_, HeapEntry::kNoEntry); gc_roots_entry_ = AddEntry(HeapEntry::kSynthetic, "(GC roots)",
HeapEntry* entry = AddEntry(HeapEntry::kSynthetic, HeapObjectsMap::kGcRootsObjectId, 0, 0);
"(GC roots)",
HeapObjectsMap::kGcRootsObjectId,
0,
0);
gc_roots_index_ = entry->index();
return entry;
} }
HeapEntry* HeapSnapshot::AddGcSubrootEntry(Root root, SnapshotObjectId id) { void HeapSnapshot::AddGcSubrootEntry(Root root, SnapshotObjectId id) {
DCHECK_EQ(gc_subroot_indexes_[static_cast<int>(root)], HeapEntry::kNoEntry); DCHECK_NULL(gc_subroot_entries_[static_cast<int>(root)]);
HeapEntry* entry = gc_subroot_entries_[static_cast<int>(root)] =
AddEntry(HeapEntry::kSynthetic, RootVisitor::RootName(root), id, 0, 0); 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) { void HeapSnapshot::AddLocation(HeapEntry* entry, int scriptId, int line,
locations_.emplace_back(entry, scriptId, line, col); int col) {
locations_.emplace_back(entry->index(), scriptId, line, col);
} }
HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
@ -258,52 +223,35 @@ HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
SnapshotObjectId id, SnapshotObjectId id,
size_t size, size_t size,
unsigned trace_node_id) { unsigned trace_node_id) {
DCHECK(sorted_entries_.empty()); DCHECK(!is_complete());
entries_.emplace_back(this, type, name, id, size, trace_node_id); entries_.emplace_back(this, static_cast<int>(entries_.size()), type, name, id,
size, trace_node_id);
return &entries_.back(); return &entries_.back();
} }
void HeapSnapshot::FillChildren() { void HeapSnapshot::FillChildren() {
DCHECK(children().empty()); DCHECK(children().empty());
children().resize(edges().size());
int children_index = 0; int children_index = 0;
for (HeapEntry& entry : entries()) { for (HeapEntry& entry : entries()) {
children_index = entry.set_children_index(children_index); children_index = entry.set_children_index(children_index);
} }
DCHECK_EQ(edges().size(), static_cast<size_t>(children_index)); DCHECK_EQ(edges().size(), static_cast<size_t>(children_index));
children().resize(edges().size());
for (HeapGraphEdge& edge : edges()) { for (HeapGraphEdge& edge : edges()) {
edge.ReplaceToIndexWithEntry(this);
edge.from()->add_child(&edge); edge.from()->add_child(&edge);
} }
} }
HeapEntry* HeapSnapshot::GetEntryById(SnapshotObjectId id) { HeapEntry* HeapSnapshot::GetEntryById(SnapshotObjectId id) {
std::vector<HeapEntry*>* entries_by_id = GetSortedEntriesList(); if (entries_by_id_cache_.empty()) {
CHECK(is_complete());
auto it = std::lower_bound( entries_by_id_cache_.reserve(entries_.size());
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());
for (HeapEntry& entry : entries_) { 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) { void HeapSnapshot::Print(int max_depth) {
@ -555,7 +503,7 @@ HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) {
return AddEntry(reinterpret_cast<HeapObject*>(ptr)); return AddEntry(reinterpret_cast<HeapObject*>(ptr));
} }
void V8HeapExplorer::ExtractLocation(int entry, HeapObject* object) { void V8HeapExplorer::ExtractLocation(HeapEntry* entry, HeapObject* object) {
if (object->IsJSFunction()) { if (object->IsJSFunction()) {
JSFunction* func = JSFunction::cast(object); JSFunction* func = JSFunction::cast(object);
ExtractLocationForJSFunction(entry, func); ExtractLocationForJSFunction(entry, func);
@ -573,7 +521,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; if (!func->shared()->script()->IsScript()) return;
Script* script = Script::cast(func->shared()->script()); Script* script = Script::cast(func->shared()->script());
int scriptId = script->id(); int scriptId = script->id();
@ -676,25 +625,20 @@ HeapEntry* V8HeapExplorer::AddEntry(Address address,
return snapshot_->AddEntry(type, name, object_id, size, trace_node_id); return snapshot_->AddEntry(type, name, object_id, size, trace_node_id);
} }
class SnapshotFiller { class SnapshotFiller {
public: public:
SnapshotFiller(HeapSnapshot* snapshot, SnapshotFiller(HeapSnapshot* snapshot,
HeapSnapshotGenerator::HeapEntriesMap* entries_map) 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* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
HeapEntry* entry = allocator->AllocateEntry(ptr); return entries_map_->emplace(ptr, allocator->AllocateEntry(ptr))
entries_map_->emplace(ptr, entry->index()); .first->second;
return entry;
} }
HeapEntry* FindEntry(HeapThing ptr) { HeapEntry* FindEntry(HeapThing ptr) {
auto it = entries_map_->find(ptr); auto it = entries_map_->find(ptr);
return it != entries_map_->end() ? &snapshot_->entries()[it->second] return it != entries_map_->end() ? it->second : nullptr;
: nullptr;
} }
HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
@ -702,43 +646,32 @@ class SnapshotFiller {
return entry != nullptr ? entry : AddEntry(ptr, allocator); return entry != nullptr ? entry : AddEntry(ptr, allocator);
} }
void SetIndexedReference(HeapGraphEdge::Type type, void SetIndexedReference(HeapGraphEdge::Type type, HeapEntry* parent,
int parent, int index, HeapEntry* child) {
int index, parent->SetIndexedReference(type, index, child);
HeapEntry* child_entry) {
HeapEntry* parent_entry = &snapshot_->entries()[parent];
parent_entry->SetIndexedReference(type, index, child_entry);
} }
void SetIndexedAutoIndexReference(HeapGraphEdge::Type type, void SetIndexedAutoIndexReference(HeapGraphEdge::Type type, HeapEntry* parent,
int parent, HeapEntry* child) {
HeapEntry* child_entry) { int index = parent->children_count() + 1;
HeapEntry* parent_entry = &snapshot_->entries()[parent]; parent->SetIndexedReference(type, index, child);
int index = parent_entry->children_count() + 1;
parent_entry->SetIndexedReference(type, index, child_entry);
} }
void SetNamedReference(HeapGraphEdge::Type type, void SetNamedReference(HeapGraphEdge::Type type, HeapEntry* parent,
int parent, const char* reference_name, HeapEntry* child) {
const char* reference_name, parent->SetNamedReference(type, reference_name, child);
HeapEntry* child_entry) {
HeapEntry* parent_entry = &snapshot_->entries()[parent];
parent_entry->SetNamedReference(type, reference_name, child_entry);
} }
void SetNamedAutoIndexReference(HeapGraphEdge::Type type, int parent, void SetNamedAutoIndexReference(HeapGraphEdge::Type type, HeapEntry* parent,
const char* description, const char* description, HeapEntry* child) {
HeapEntry* child_entry) { int index = parent->children_count() + 1;
HeapEntry* parent_entry = &snapshot_->entries()[parent];
int index = parent_entry->children_count() + 1;
const char* name = description const char* name = description
? names_->GetFormatted("%d / %s", index, description) ? names_->GetFormatted("%d / %s", index, description)
: names_->GetName(index); : names_->GetName(index);
parent_entry->SetNamedReference(type, name, child_entry); parent->SetNamedReference(type, name, child);
} }
private: private:
HeapSnapshot* snapshot_;
StringsStorage* names_; StringsStorage* names_;
HeapSnapshotGenerator::HeapEntriesMap* entries_map_; HeapSnapshotGenerator::HeapEntriesMap* entries_map_;
}; };
@ -778,7 +711,7 @@ int V8HeapExplorer::EstimateObjectsCount() {
class IndexedReferencesExtractor : public ObjectVisitor { class IndexedReferencesExtractor : public ObjectVisitor {
public: public:
IndexedReferencesExtractor(V8HeapExplorer* generator, HeapObject* parent_obj, IndexedReferencesExtractor(V8HeapExplorer* generator, HeapObject* parent_obj,
int parent) HeapEntry* parent)
: generator_(generator), : generator_(generator),
parent_obj_(parent_obj), parent_obj_(parent_obj),
parent_start_(HeapObject::RawField(parent_obj_, 0)), parent_start_(HeapObject::RawField(parent_obj_, 0)),
@ -817,10 +750,10 @@ class IndexedReferencesExtractor : public ObjectVisitor {
HeapObject* parent_obj_; HeapObject* parent_obj_;
Object** parent_start_; Object** parent_start_;
Object** parent_end_; Object** parent_end_;
int parent_; HeapEntry* parent_;
}; };
void V8HeapExplorer::ExtractReferences(int entry, HeapObject* obj) { void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject* obj) {
if (obj->IsJSGlobalProxy()) { if (obj->IsJSGlobalProxy()) {
ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj)); ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
} else if (obj->IsJSArrayBuffer()) { } else if (obj->IsJSArrayBuffer()) {
@ -884,17 +817,15 @@ void V8HeapExplorer::ExtractReferences(int entry, HeapObject* obj) {
} }
} }
void V8HeapExplorer::ExtractJSGlobalProxyReferences(HeapEntry* entry,
void V8HeapExplorer::ExtractJSGlobalProxyReferences( JSGlobalProxy* proxy) {
int entry, JSGlobalProxy* proxy) {
SetInternalReference(proxy, entry, SetInternalReference(proxy, entry,
"native_context", proxy->native_context(), "native_context", proxy->native_context(),
JSGlobalProxy::kNativeContextOffset); JSGlobalProxy::kNativeContextOffset);
} }
void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry,
void V8HeapExplorer::ExtractJSObjectReferences( JSObject* js_obj) {
int entry, JSObject* js_obj) {
HeapObject* obj = js_obj; HeapObject* obj = js_obj;
ExtractPropertyReferences(js_obj, entry); ExtractPropertyReferences(js_obj, entry);
ExtractElementReferences(js_obj, entry); ExtractElementReferences(js_obj, entry);
@ -977,8 +908,7 @@ void V8HeapExplorer::ExtractJSObjectReferences(
JSObject::kElementsOffset); JSObject::kElementsOffset);
} }
void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, String* string) {
void V8HeapExplorer::ExtractStringReferences(int entry, String* string) {
if (string->IsConsString()) { if (string->IsConsString()) {
ConsString* cs = ConsString::cast(string); ConsString* cs = ConsString::cast(string);
SetInternalReference(cs, entry, "first", cs->first(), SetInternalReference(cs, entry, "first", cs->first(),
@ -996,28 +926,26 @@ void V8HeapExplorer::ExtractStringReferences(int entry, String* string) {
} }
} }
void V8HeapExplorer::ExtractSymbolReferences(HeapEntry* entry, Symbol* symbol) {
void V8HeapExplorer::ExtractSymbolReferences(int entry, Symbol* symbol) {
SetInternalReference(symbol, entry, SetInternalReference(symbol, entry,
"name", symbol->name(), "name", symbol->name(),
Symbol::kNameOffset); Symbol::kNameOffset);
} }
void V8HeapExplorer::ExtractJSCollectionReferences(HeapEntry* entry,
void V8HeapExplorer::ExtractJSCollectionReferences(int entry,
JSCollection* collection) { JSCollection* collection) {
SetInternalReference(collection, entry, "table", collection->table(), SetInternalReference(collection, entry, "table", collection->table(),
JSCollection::kTableOffset); JSCollection::kTableOffset);
} }
void V8HeapExplorer::ExtractJSWeakCollectionReferences(int entry, void V8HeapExplorer::ExtractJSWeakCollectionReferences(HeapEntry* entry,
JSWeakCollection* obj) { JSWeakCollection* obj) {
SetInternalReference(obj, entry, "table", obj->table(), SetInternalReference(obj, entry, "table", obj->table(),
JSWeakCollection::kTableOffset); JSWeakCollection::kTableOffset);
} }
void V8HeapExplorer::ExtractEphemeronHashTableReferences( void V8HeapExplorer::ExtractEphemeronHashTableReferences(
int entry, EphemeronHashTable* table) { HeapEntry* entry, EphemeronHashTable* table) {
for (int i = 0, capacity = table->Capacity(); i < capacity; ++i) { for (int i = 0, capacity = table->Capacity(); i < capacity; ++i) {
int key_index = EphemeronHashTable::EntryToIndex(i) + int key_index = EphemeronHashTable::EntryToIndex(i) +
EphemeronHashTable::kEntryKeyIndex; EphemeronHashTable::kEntryKeyIndex;
@ -1029,18 +957,18 @@ void V8HeapExplorer::ExtractEphemeronHashTableReferences(
SetWeakReference(table, entry, value_index, value, SetWeakReference(table, entry, value_index, value,
table->OffsetOfElementAt(value_index)); table->OffsetOfElementAt(value_index));
HeapEntry* key_entry = GetEntry(key); HeapEntry* key_entry = GetEntry(key);
int key_entry_index = key_entry->index();
HeapEntry* value_entry = GetEntry(value); HeapEntry* value_entry = GetEntry(value);
if (key_entry && value_entry) { if (key_entry && value_entry) {
const char* edge_name = const char* edge_name =
names_->GetFormatted("key %s in WeakMap", key_entry->name()); names_->GetFormatted("key %s in WeakMap", key_entry->name());
filler_->SetNamedAutoIndexReference( filler_->SetNamedAutoIndexReference(HeapGraphEdge::kInternal, key_entry,
HeapGraphEdge::kInternal, key_entry_index, edge_name, value_entry); edge_name, value_entry);
} }
} }
} }
void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) { void V8HeapExplorer::ExtractContextReferences(HeapEntry* entry,
Context* context) {
if (!context->IsNativeContext() && context->is_declaration_context()) { if (!context->IsNativeContext() && context->is_declaration_context()) {
ScopeInfo* scope_info = context->scope_info(); ScopeInfo* scope_info = context->scope_info();
// Add context allocated locals. // Add context allocated locals.
@ -1089,8 +1017,7 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
} }
} }
void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) {
void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
MaybeObject* maybe_raw_transitions_or_prototype_info = map->raw_transitions(); MaybeObject* maybe_raw_transitions_or_prototype_info = map->raw_transitions();
HeapObject* raw_transitions_or_prototype_info; HeapObject* raw_transitions_or_prototype_info;
if (maybe_raw_transitions_or_prototype_info->GetHeapObjectIfWeak( if (maybe_raw_transitions_or_prototype_info->GetHeapObjectIfWeak(
@ -1154,9 +1081,8 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
Map::kDependentCodeOffset); Map::kDependentCodeOffset);
} }
void V8HeapExplorer::ExtractSharedFunctionInfoReferences( void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
int entry, SharedFunctionInfo* shared) { HeapEntry* entry, SharedFunctionInfo* shared) {
HeapObject* obj = shared; HeapObject* obj = shared;
String* shared_name = shared->DebugName(); String* shared_name = shared->DebugName();
const char* name = nullptr; const char* name = nullptr;
@ -1187,7 +1113,7 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset); SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset);
} }
void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) { void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) {
HeapObject* obj = script; HeapObject* obj = script;
SetInternalReference(obj, entry, SetInternalReference(obj, entry,
"source", script->source(), "source", script->source(),
@ -1204,9 +1130,8 @@ void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) {
Script::kLineEndsOffset); Script::kLineEndsOffset);
} }
void V8HeapExplorer::ExtractAccessorInfoReferences( void V8HeapExplorer::ExtractAccessorInfoReferences(
int entry, AccessorInfo* accessor_info) { HeapEntry* entry, AccessorInfo* accessor_info) {
SetInternalReference(accessor_info, entry, "name", accessor_info->name(), SetInternalReference(accessor_info, entry, "name", accessor_info->name(),
AccessorInfo::kNameOffset); AccessorInfo::kNameOffset);
SetInternalReference(accessor_info, entry, "expected_receiver_type", SetInternalReference(accessor_info, entry, "expected_receiver_type",
@ -1220,8 +1145,8 @@ void V8HeapExplorer::ExtractAccessorInfoReferences(
AccessorInfo::kDataOffset); AccessorInfo::kDataOffset);
} }
void V8HeapExplorer::ExtractAccessorPairReferences( void V8HeapExplorer::ExtractAccessorPairReferences(HeapEntry* entry,
int entry, AccessorPair* accessors) { AccessorPair* accessors) {
SetInternalReference(accessors, entry, "getter", accessors->getter(), SetInternalReference(accessors, entry, "getter", accessors->getter(),
AccessorPair::kGetterOffset); AccessorPair::kGetterOffset);
SetInternalReference(accessors, entry, "setter", accessors->setter(), SetInternalReference(accessors, entry, "setter", accessors->setter(),
@ -1240,7 +1165,7 @@ void V8HeapExplorer::TagCodeObject(Code* code) {
} }
} }
void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) { void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code* code) {
TagCodeObject(code); TagCodeObject(code);
TagObject(code->relocation_info(), "(code relocation info)"); TagObject(code->relocation_info(), "(code relocation info)");
SetInternalReference(code, entry, SetInternalReference(code, entry,
@ -1256,18 +1181,18 @@ void V8HeapExplorer::ExtractCodeReferences(int entry, Code* code) {
Code::kSourcePositionTableOffset); Code::kSourcePositionTableOffset);
} }
void V8HeapExplorer::ExtractCellReferences(int entry, Cell* cell) { void V8HeapExplorer::ExtractCellReferences(HeapEntry* entry, Cell* cell) {
SetInternalReference(cell, entry, "value", cell->value(), Cell::kValueOffset); SetInternalReference(cell, entry, "value", cell->value(), Cell::kValueOffset);
} }
void V8HeapExplorer::ExtractFeedbackCellReferences( void V8HeapExplorer::ExtractFeedbackCellReferences(
int entry, FeedbackCell* feedback_cell) { HeapEntry* entry, FeedbackCell* feedback_cell) {
TagObject(feedback_cell, "(feedback cell)"); TagObject(feedback_cell, "(feedback cell)");
SetInternalReference(feedback_cell, entry, "value", feedback_cell->value(), SetInternalReference(feedback_cell, entry, "value", feedback_cell->value(),
FeedbackCell::kValueOffset); FeedbackCell::kValueOffset);
} }
void V8HeapExplorer::ExtractPropertyCellReferences(int entry, void V8HeapExplorer::ExtractPropertyCellReferences(HeapEntry* entry,
PropertyCell* cell) { PropertyCell* cell) {
SetInternalReference(cell, entry, "value", cell->value(), SetInternalReference(cell, entry, "value", cell->value(),
PropertyCell::kValueOffset); PropertyCell::kValueOffset);
@ -1276,7 +1201,7 @@ void V8HeapExplorer::ExtractPropertyCellReferences(int entry,
PropertyCell::kDependentCodeOffset); PropertyCell::kDependentCodeOffset);
} }
void V8HeapExplorer::ExtractAllocationSiteReferences(int entry, void V8HeapExplorer::ExtractAllocationSiteReferences(HeapEntry* entry,
AllocationSite* site) { AllocationSite* site) {
SetInternalReference(site, entry, "transition_info", SetInternalReference(site, entry, "transition_info",
site->transition_info_or_boilerplate(), site->transition_info_or_boilerplate(),
@ -1289,7 +1214,7 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(int entry,
} }
void V8HeapExplorer::ExtractArrayBoilerplateDescriptionReferences( void V8HeapExplorer::ExtractArrayBoilerplateDescriptionReferences(
int entry, ArrayBoilerplateDescription* value) { HeapEntry* entry, ArrayBoilerplateDescription* value) {
SetInternalReference(value, entry, "constant_elements", SetInternalReference(value, entry, "constant_elements",
value->constant_elements(), value->constant_elements(),
ArrayBoilerplateDescription::kConstantElementsOffset); ArrayBoilerplateDescription::kConstantElementsOffset);
@ -1311,8 +1236,8 @@ class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator {
V8HeapExplorer* explorer_; V8HeapExplorer* explorer_;
}; };
void V8HeapExplorer::ExtractJSArrayBufferReferences( void V8HeapExplorer::ExtractJSArrayBufferReferences(HeapEntry* entry,
int entry, JSArrayBuffer* buffer) { JSArrayBuffer* buffer) {
// Setup a reference to a native memory backing_store object. // Setup a reference to a native memory backing_store object.
if (!buffer->backing_store()) if (!buffer->backing_store())
return; return;
@ -1324,14 +1249,15 @@ void V8HeapExplorer::ExtractJSArrayBufferReferences(
entry, "backing_store", data_entry); 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", SetInternalReference(promise, entry, "reactions_or_result",
promise->reactions_or_result(), promise->reactions_or_result(),
JSPromise::kReactionsOrResultOffset); JSPromise::kReactionsOrResultOffset);
} }
void V8HeapExplorer::ExtractJSGeneratorObjectReferences( void V8HeapExplorer::ExtractJSGeneratorObjectReferences(
int entry, JSGeneratorObject* generator) { HeapEntry* entry, JSGeneratorObject* generator) {
SetInternalReference(generator, entry, "function", generator->function(), SetInternalReference(generator, entry, "function", generator->function(),
JSGeneratorObject::kFunctionOffset); JSGeneratorObject::kFunctionOffset);
SetInternalReference(generator, entry, "context", generator->context(), SetInternalReference(generator, entry, "context", generator->context(),
@ -1343,7 +1269,8 @@ void V8HeapExplorer::ExtractJSGeneratorObjectReferences(
JSGeneratorObject::kParametersAndRegistersOffset); 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) { for (int i = 0, l = array->length(); i < l; ++i) {
DCHECK(!HasWeakHeapObjectTag(array->get(i))); DCHECK(!HasWeakHeapObjectTag(array->get(i)));
SetInternalReference(array, entry, i, array->get(i), SetInternalReference(array, entry, i, array->get(i),
@ -1352,7 +1279,7 @@ void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) {
} }
void V8HeapExplorer::ExtractFeedbackVectorReferences( void V8HeapExplorer::ExtractFeedbackVectorReferences(
int entry, FeedbackVector* feedback_vector) { HeapEntry* entry, FeedbackVector* feedback_vector) {
MaybeObject* code = feedback_vector->optimized_code_weak_or_smi(); MaybeObject* code = feedback_vector->optimized_code_weak_or_smi();
HeapObject* code_heap_object; HeapObject* code_heap_object;
if (code->GetHeapObjectIfWeak(&code_heap_object)) { if (code->GetHeapObjectIfWeak(&code_heap_object)) {
@ -1362,8 +1289,8 @@ void V8HeapExplorer::ExtractFeedbackVectorReferences(
} }
template <typename T> template <typename T>
void V8HeapExplorer::ExtractWeakArrayReferences(int header_size, int entry, void V8HeapExplorer::ExtractWeakArrayReferences(int header_size,
T* array) { HeapEntry* entry, T* array) {
for (int i = 0; i < array->length(); ++i) { for (int i = 0; i < array->length(); ++i) {
MaybeObject* object = array->Get(i); MaybeObject* object = array->Get(i);
HeapObject* heap_object; HeapObject* heap_object;
@ -1377,7 +1304,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(); Isolate* isolate = js_obj->GetIsolate();
if (js_obj->HasFastProperties()) { if (js_obj->HasFastProperties()) {
DescriptorArray* descs = js_obj->map()->instance_descriptors(); DescriptorArray* descs = js_obj->map()->instance_descriptors();
@ -1438,9 +1366,8 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
} }
} }
void V8HeapExplorer::ExtractAccessorPairProperty(JSObject* js_obj,
void V8HeapExplorer::ExtractAccessorPairProperty(JSObject* js_obj, int entry, HeapEntry* entry, Name* key,
Name* key,
Object* callback_obj, Object* callback_obj,
int field_offset) { int field_offset) {
if (!callback_obj->IsAccessorPair()) return; if (!callback_obj->IsAccessorPair()) return;
@ -1456,8 +1383,8 @@ void V8HeapExplorer::ExtractAccessorPairProperty(JSObject* js_obj, int entry,
} }
} }
void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj,
void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) { HeapEntry* entry) {
ReadOnlyRoots roots = js_obj->GetReadOnlyRoots(); ReadOnlyRoots roots = js_obj->GetReadOnlyRoots();
if (js_obj->HasObjectElements()) { if (js_obj->HasObjectElements()) {
FixedArray* elements = FixedArray::cast(js_obj->elements()); FixedArray* elements = FixedArray::cast(js_obj->elements());
@ -1483,8 +1410,8 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) {
} }
} }
void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj,
void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, int entry) { HeapEntry* entry) {
int length = js_obj->GetEmbedderFieldCount(); int length = js_obj->GetEmbedderFieldCount();
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i) {
Object* o = js_obj->GetEmbedderField(i); Object* o = js_obj->GetEmbedderField(i);
@ -1579,8 +1506,7 @@ bool V8HeapExplorer::IterateAndExtractReferences(SnapshotFiller* filler) {
visited_fields_.resize(max_pointer, false); visited_fields_.resize(max_pointer, false);
} }
HeapEntry* heap_entry = GetEntry(obj); HeapEntry* entry = GetEntry(obj);
int entry = heap_entry->index();
ExtractReferences(entry, obj); ExtractReferences(entry, obj);
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
// Extract unvisited fields as hidden references and restore tags // Extract unvisited fields as hidden references and restore tags
@ -1634,11 +1560,10 @@ bool V8HeapExplorer::IsEssentialHiddenReference(Object* parent,
} }
void V8HeapExplorer::SetContextReference(HeapObject* parent_obj, void V8HeapExplorer::SetContextReference(HeapObject* parent_obj,
int parent_entry, HeapEntry* parent_entry,
String* reference_name, String* reference_name,
Object* child_obj, Object* child_obj, int field_offset) {
int field_offset) { DCHECK_EQ(parent_entry, GetEntry(parent_obj));
DCHECK(parent_entry == GetEntry(parent_obj)->index());
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry == nullptr) return; if (child_entry == nullptr) return;
filler_->SetNamedReference(HeapGraphEdge::kContextVariable, parent_entry, filler_->SetNamedReference(HeapGraphEdge::kContextVariable, parent_entry,
@ -1653,37 +1578,32 @@ void V8HeapExplorer::MarkVisitedField(int offset) {
visited_fields_[index] = true; visited_fields_[index] = true;
} }
void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj, void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj,
int parent_entry, HeapEntry* parent_entry,
const char* reference_name, const char* reference_name,
Object* child_obj) { Object* child_obj) {
DCHECK(parent_entry == GetEntry(parent_obj)->index()); DCHECK_EQ(parent_entry, GetEntry(parent_obj));
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry == nullptr) return; if (child_entry == nullptr) return;
filler_->SetNamedReference(HeapGraphEdge::kShortcut, parent_entry, filler_->SetNamedReference(HeapGraphEdge::kShortcut, parent_entry,
reference_name, child_entry); reference_name, child_entry);
} }
void V8HeapExplorer::SetElementReference(HeapObject* parent_obj, void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
int parent_entry, HeapEntry* parent_entry, int index,
int index,
Object* child_obj) { Object* child_obj) {
DCHECK(parent_entry == GetEntry(parent_obj)->index()); DCHECK_EQ(parent_entry, GetEntry(parent_obj));
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry == nullptr) return; if (child_entry == nullptr) return;
filler_->SetIndexedReference(HeapGraphEdge::kElement, parent_entry, index, filler_->SetIndexedReference(HeapGraphEdge::kElement, parent_entry, index,
child_entry); child_entry);
} }
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
int parent_entry, HeapEntry* parent_entry,
const char* reference_name, const char* reference_name,
Object* child_obj, Object* child_obj, int field_offset) {
int field_offset) { DCHECK_EQ(parent_entry, GetEntry(parent_obj));
DCHECK(parent_entry == GetEntry(parent_obj)->index());
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry == nullptr) return; if (child_entry == nullptr) return;
if (IsEssentialObject(child_obj)) { if (IsEssentialObject(child_obj)) {
@ -1695,13 +1615,10 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
MarkVisitedField(field_offset); MarkVisitedField(field_offset);
} }
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
int parent_entry, HeapEntry* parent_entry, int index,
int index, Object* child_obj, int field_offset) {
Object* child_obj, DCHECK_EQ(parent_entry, GetEntry(parent_obj));
int field_offset) {
DCHECK(parent_entry == GetEntry(parent_obj)->index());
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry == nullptr) return; if (child_entry == nullptr) return;
if (IsEssentialObject(child_obj)) { if (IsEssentialObject(child_obj)) {
@ -1714,9 +1631,9 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
} }
void V8HeapExplorer::SetHiddenReference(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) { 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); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != nullptr && IsEssentialObject(child_obj) && if (child_entry != nullptr && IsEssentialObject(child_obj) &&
IsEssentialHiddenReference(parent_obj, field_offset)) { IsEssentialHiddenReference(parent_obj, field_offset)) {
@ -1725,13 +1642,11 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
} }
} }
void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
int parent_entry, HeapEntry* parent_entry,
const char* reference_name, const char* reference_name,
Object* child_obj, Object* child_obj, int field_offset) {
int field_offset) { DCHECK_EQ(parent_entry, GetEntry(parent_obj));
DCHECK(parent_entry == GetEntry(parent_obj)->index());
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry == nullptr) return; if (child_entry == nullptr) return;
if (IsEssentialObject(child_obj)) { if (IsEssentialObject(child_obj)) {
@ -1743,13 +1658,10 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
MarkVisitedField(field_offset); MarkVisitedField(field_offset);
} }
void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
int parent_entry, HeapEntry* parent_entry, int index,
int index, Object* child_obj, int field_offset) {
Object* child_obj, DCHECK_EQ(parent_entry, GetEntry(parent_obj));
int field_offset) {
DCHECK(parent_entry == GetEntry(parent_obj)->index());
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry == nullptr) return; if (child_entry == nullptr) return;
if (IsEssentialObject(child_obj)) { if (IsEssentialObject(child_obj)) {
@ -1762,9 +1674,10 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
} }
void V8HeapExplorer::SetDataOrAccessorPropertyReference( 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, Name* reference_name, Object* child_obj, const char* name_format_string,
int field_offset) { int field_offset) {
DCHECK_EQ(parent_entry, GetEntry(parent_obj));
if (kind == kAccessor) { if (kind == kAccessor) {
ExtractAccessorPairProperty(parent_obj, parent_entry, reference_name, ExtractAccessorPairProperty(parent_obj, parent_entry, reference_name,
child_obj, field_offset); child_obj, field_offset);
@ -1774,14 +1687,10 @@ void V8HeapExplorer::SetDataOrAccessorPropertyReference(
} }
} }
void V8HeapExplorer::SetPropertyReference(
void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, HeapObject* parent_obj, HeapEntry* parent_entry, Name* reference_name,
int parent_entry, Object* child_obj, const char* name_format_string, int field_offset) {
Name* reference_name, DCHECK_EQ(parent_entry, GetEntry(parent_obj));
Object* child_obj,
const char* name_format_string,
int field_offset) {
DCHECK(parent_entry == GetEntry(parent_obj)->index());
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry == nullptr) return; if (child_entry == nullptr) return;
HeapGraphEdge::Type type = HeapGraphEdge::Type type =
@ -1803,22 +1712,19 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
void V8HeapExplorer::SetRootGcRootsReference() { void V8HeapExplorer::SetRootGcRootsReference() {
filler_->SetIndexedAutoIndexReference( filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement, HeapGraphEdge::kElement, snapshot_->root(), snapshot_->gc_roots());
snapshot_->root()->index(),
snapshot_->gc_roots());
} }
void V8HeapExplorer::SetUserGlobalReference(Object* child_obj) { void V8HeapExplorer::SetUserGlobalReference(Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
DCHECK_NOT_NULL(child_entry); DCHECK_NOT_NULL(child_entry);
filler_->SetNamedAutoIndexReference(HeapGraphEdge::kShortcut, filler_->SetNamedAutoIndexReference(HeapGraphEdge::kShortcut,
snapshot_->root()->index(), nullptr, snapshot_->root(), nullptr, child_entry);
child_entry);
} }
void V8HeapExplorer::SetGcRootsReference(Root root) { void V8HeapExplorer::SetGcRootsReference(Root root) {
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
snapshot_->gc_roots()->index(), snapshot_->gc_roots(),
snapshot_->gc_subroot(root)); snapshot_->gc_subroot(root));
} }
@ -1830,11 +1736,10 @@ void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description,
HeapGraphEdge::Type edge_type = HeapGraphEdge::Type edge_type =
is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kInternal; is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kInternal;
if (name != nullptr) { if (name != nullptr) {
filler_->SetNamedReference(edge_type, snapshot_->gc_subroot(root)->index(), filler_->SetNamedReference(edge_type, snapshot_->gc_subroot(root), name,
name, child_entry); child_entry);
} else { } else {
filler_->SetNamedAutoIndexReference(edge_type, filler_->SetNamedAutoIndexReference(edge_type, snapshot_->gc_subroot(root),
snapshot_->gc_subroot(root)->index(),
description, child_entry); description, child_entry);
} }
@ -2171,10 +2076,9 @@ void NativeObjectsExplorer::FillEdges() {
Handle<Object> parent_object = v8::Utils::OpenHandle( Handle<Object> parent_object = v8::Utils::OpenHandle(
*pair.first->Get(reinterpret_cast<v8::Isolate*>(isolate_))); *pair.first->Get(reinterpret_cast<v8::Isolate*>(isolate_)));
HeapObject* parent = HeapObject::cast(*parent_object); HeapObject* parent = HeapObject::cast(*parent_object);
int parent_entry = HeapEntry* parent_entry =
filler_->FindOrAddEntry(parent, native_entries_allocator_.get()) filler_->FindOrAddEntry(parent, native_entries_allocator_.get());
->index(); DCHECK_NOT_NULL(parent_entry);
DCHECK_NE(parent_entry, HeapEntry::kNoEntry);
Handle<Object> child_object = v8::Utils::OpenHandle( Handle<Object> child_object = v8::Utils::OpenHandle(
*pair.second->Get(reinterpret_cast<v8::Isolate*>(isolate_))); *pair.second->Get(reinterpret_cast<v8::Isolate*>(isolate_)));
HeapObject* child = HeapObject::cast(*child_object); HeapObject* child = HeapObject::cast(*child_object);
@ -2227,7 +2131,7 @@ bool NativeObjectsExplorer::IterateAndExtractReferences(
for (const auto& node : graph.nodes()) { for (const auto& node : graph.nodes()) {
if (node->IsRootNode()) { if (node->IsRootNode()) {
filler_->SetIndexedAutoIndexReference( filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement, snapshot_->root()->index(), HeapGraphEdge::kElement, snapshot_->root(),
EntryForEmbedderGraphNode(node.get())); EntryForEmbedderGraphNode(node.get()));
} }
// Adjust the name and the type of the V8 wrapper node. // Adjust the name and the type of the V8 wrapper node.
@ -2246,17 +2150,14 @@ bool NativeObjectsExplorer::IterateAndExtractReferences(
// The |from| and |to| can nullptr if the corrsponding node is a V8 node // The |from| and |to| can nullptr if the corrsponding node is a V8 node
// pointing to a Smi. // pointing to a Smi.
if (!from) continue; 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); HeapEntry* to = EntryForEmbedderGraphNode(edge.to);
if (to) { if (to) {
if (edge.name == nullptr) { if (edge.name == nullptr) {
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, from,
from_index, to); to);
} else { } else {
filler_->SetNamedReference(HeapGraphEdge::kInternal, from_index, filler_->SetNamedReference(HeapGraphEdge::kInternal, from, edge.name,
edge.name, to); to);
} }
} }
} }
@ -2297,11 +2198,8 @@ void NativeObjectsExplorer::SetNativeRootReference(
FindOrAddGroupInfo(info->GetGroupLabel()); FindOrAddGroupInfo(info->GetGroupLabel());
HeapEntry* group_entry = HeapEntry* group_entry =
filler_->FindOrAddEntry(group_info, synthetic_entries_allocator_.get()); filler_->FindOrAddEntry(group_info, synthetic_entries_allocator_.get());
// |FindOrAddEntry| can move and resize the entries backing store. Reload filler_->SetNamedAutoIndexReference(HeapGraphEdge::kInternal, group_entry,
// potentially-stale pointer. nullptr, child_entry);
child_entry = filler_->FindEntry(info);
filler_->SetNamedAutoIndexReference(
HeapGraphEdge::kInternal, group_entry->index(), nullptr, child_entry);
} }
@ -2312,12 +2210,9 @@ void NativeObjectsExplorer::SetWrapperNativeReferences(
HeapEntry* info_entry = HeapEntry* info_entry =
filler_->FindOrAddEntry(info, native_entries_allocator_.get()); filler_->FindOrAddEntry(info, native_entries_allocator_.get());
DCHECK_NOT_NULL(info_entry); DCHECK_NOT_NULL(info_entry);
filler_->SetNamedReference(HeapGraphEdge::kInternal, filler_->SetNamedReference(HeapGraphEdge::kInternal, wrapper_entry, "native",
wrapper_entry->index(),
"native",
info_entry); info_entry);
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, info_entry,
info_entry->index(),
wrapper_entry); wrapper_entry);
} }
@ -2328,10 +2223,8 @@ void NativeObjectsExplorer::SetRootNativeRootsReference() {
HeapEntry* group_entry = HeapEntry* group_entry =
filler_->FindOrAddEntry(group_info, native_entries_allocator_.get()); filler_->FindOrAddEntry(group_info, native_entries_allocator_.get());
DCHECK_NOT_NULL(group_entry); DCHECK_NOT_NULL(group_entry);
filler_->SetIndexedAutoIndexReference( filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
HeapGraphEdge::kElement, snapshot_->root(), group_entry);
snapshot_->root()->index(),
group_entry);
} }
} }
@ -2678,9 +2571,8 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
writer_->AddString(buffer.start()); writer_->AddString(buffer.start());
} }
void HeapSnapshotJSONSerializer::SerializeEdges() { void HeapSnapshotJSONSerializer::SerializeEdges() {
std::deque<HeapGraphEdge*>& edges = snapshot_->children(); std::vector<HeapGraphEdge*>& edges = snapshot_->children();
for (size_t i = 0; i < edges.size(); ++i) { for (size_t i = 0; i < edges.size(); ++i) {
DCHECK(i == 0 || DCHECK(i == 0 ||
edges[i - 1]->from()->index() <= edges[i]->from()->index()); edges[i - 1]->from()->index() <= edges[i]->from()->index());
@ -2716,16 +2608,14 @@ void HeapSnapshotJSONSerializer::SerializeNode(const HeapEntry* entry) {
writer_->AddString(buffer.start()); writer_->AddString(buffer.start());
} }
void HeapSnapshotJSONSerializer::SerializeNodes() { void HeapSnapshotJSONSerializer::SerializeNodes() {
std::vector<HeapEntry>& entries = snapshot_->entries(); const std::deque<HeapEntry>& entries = snapshot_->entries();
for (const HeapEntry& entry : entries) { for (const HeapEntry& entry : entries) {
SerializeNode(&entry); SerializeNode(&entry);
if (writer_->aborted()) return; if (writer_->aborted()) return;
} }
} }
void HeapSnapshotJSONSerializer::SerializeSnapshot() { void HeapSnapshotJSONSerializer::SerializeSnapshot() {
writer_->AddString("\"meta\":"); writer_->AddString("\"meta\":");
// The object describing node serialization layout. // The object describing node serialization layout.

View File

@ -60,9 +60,8 @@ class HeapGraphEdge {
kWeak = v8::HeapGraphEdge::kWeak kWeak = v8::HeapGraphEdge::kWeak
}; };
HeapGraphEdge(Type type, const char* name, int from, int to); HeapGraphEdge(Type type, const char* name, HeapEntry* from, HeapEntry* to);
HeapGraphEdge(Type type, int index, int from, int to); HeapGraphEdge(Type type, int index, HeapEntry* from, HeapEntry* to);
void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);
Type type() const { return TypeField::decode(bit_field_); } Type type() const { return TypeField::decode(bit_field_); }
int index() const { int index() const {
@ -86,12 +85,7 @@ class HeapGraphEdge {
class TypeField : public BitField<Type, 0, 3> {}; class TypeField : public BitField<Type, 0, 3> {};
class FromIndexField : public BitField<int, 3, 29> {}; class FromIndexField : public BitField<int, 3, 29> {};
uint32_t bit_field_; uint32_t bit_field_;
union { HeapEntry* to_entry_;
// 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_;
};
union { union {
int index_; int index_;
const char* name_; const char* name_;
@ -119,15 +113,9 @@ class HeapEntry {
kSymbol = v8::HeapGraphNode::kSymbol, kSymbol = v8::HeapGraphNode::kSymbol,
kBigInt = v8::HeapGraphNode::kBigInt kBigInt = v8::HeapGraphNode::kBigInt
}; };
static const int kNoEntry;
HeapEntry() = default; HeapEntry(HeapSnapshot* snapshot, int index, Type type, const char* name,
HeapEntry(HeapSnapshot* snapshot, SnapshotObjectId id, size_t self_size, unsigned trace_node_id);
Type type,
const char* name,
SnapshotObjectId id,
size_t self_size,
unsigned trace_node_id);
HeapSnapshot* snapshot() { return snapshot_; } HeapSnapshot* snapshot() { return snapshot_; }
Type type() const { return static_cast<Type>(type_); } Type type() const { return static_cast<Type>(type_); }
@ -137,8 +125,8 @@ class HeapEntry {
SnapshotObjectId id() const { return id_; } SnapshotObjectId id() const { return id_; }
size_t self_size() const { return self_size_; } size_t self_size() const { return self_size_; }
unsigned trace_node_id() const { return trace_node_id_; } unsigned trace_node_id() const { return trace_node_id_; }
V8_INLINE int index() const; int index() const { return index_; }
int children_count() const { return children_count_; } V8_INLINE int children_count() const;
V8_INLINE int set_children_index(int index); V8_INLINE int set_children_index(int index);
V8_INLINE void add_child(HeapGraphEdge* edge); V8_INLINE void add_child(HeapGraphEdge* edge);
V8_INLINE HeapGraphEdge* child(int i); V8_INLINE HeapGraphEdge* child(int i);
@ -153,13 +141,18 @@ class HeapEntry {
const char* prefix, const char* edge_name, int max_depth, int indent); const char* prefix, const char* edge_name, int max_depth, int indent);
private: private:
V8_INLINE std::deque<HeapGraphEdge*>::iterator children_begin(); V8_INLINE std::vector<HeapGraphEdge*>::iterator children_begin() const;
V8_INLINE std::deque<HeapGraphEdge*>::iterator children_end(); V8_INLINE std::vector<HeapGraphEdge*>::iterator children_end() const;
const char* TypeAsString(); const char* TypeAsString();
unsigned type_: 4; unsigned type_: 4;
int children_count_: 28; unsigned index_ : 28; // Supports up to ~250M objects.
int children_index_; union {
// The count is used during the snapshot build phase,
// then it gets converted into the index by the |FillChildren| function.
unsigned children_count_ = 0;
unsigned children_end_index_;
};
size_t self_size_; size_t self_size_;
HeapSnapshot* snapshot_; HeapSnapshot* snapshot_;
const char* name_; const char* name_;
@ -168,7 +161,6 @@ class HeapEntry {
unsigned trace_node_id_; unsigned trace_node_id_;
}; };
// HeapSnapshot represents a single heap snapshot. It is stored in // HeapSnapshot represents a single heap snapshot. It is stored in
// HeapProfiler, which is also a factory for // HeapProfiler, which is also a factory for
// HeapSnapshots. All HeapSnapshots share strings copied from JS heap // HeapSnapshots. All HeapSnapshots share strings copied from JS heap
@ -179,22 +171,23 @@ class HeapSnapshot {
explicit HeapSnapshot(HeapProfiler* profiler); explicit HeapSnapshot(HeapProfiler* profiler);
void Delete(); void Delete();
HeapProfiler* profiler() { return profiler_; } HeapProfiler* profiler() const { return profiler_; }
HeapEntry* root() { return &entries_[root_index_]; } HeapEntry* root() const { return root_entry_; }
HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; } HeapEntry* gc_roots() const { return gc_roots_entry_; }
HeapEntry* gc_subroot(Root root) { HeapEntry* gc_subroot(Root root) const {
return &entries_[gc_subroot_indexes_[static_cast<int>(root)]]; 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>& edges() { return edges_; }
std::deque<HeapGraphEdge*>& children() { return children_; } std::vector<HeapGraphEdge*>& children() { return children_; }
const std::vector<SourceLocation>& locations() const { return locations_; } const std::vector<SourceLocation>& locations() const { return locations_; }
void RememberLastJSObjectId(); void RememberLastJSObjectId();
SnapshotObjectId max_snapshot_js_object_id() const { SnapshotObjectId max_snapshot_js_object_id() const {
return max_snapshot_js_object_id_; 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, HeapEntry* AddEntry(HeapEntry::Type type,
const char* name, const char* name,
SnapshotObjectId id, SnapshotObjectId id,
@ -202,28 +195,28 @@ class HeapSnapshot {
unsigned trace_node_id); unsigned trace_node_id);
void AddSyntheticRootEntries(); void AddSyntheticRootEntries();
HeapEntry* GetEntryById(SnapshotObjectId id); HeapEntry* GetEntryById(SnapshotObjectId id);
std::vector<HeapEntry*>* GetSortedEntriesList();
void FillChildren(); void FillChildren();
void Print(int max_depth); void Print(int max_depth);
private: private:
HeapEntry* AddRootEntry(); void AddRootEntry();
HeapEntry* AddGcRootsEntry(); void AddGcRootsEntry();
HeapEntry* AddGcSubrootEntry(Root root, SnapshotObjectId id); void AddGcSubrootEntry(Root root, SnapshotObjectId id);
HeapProfiler* profiler_; HeapProfiler* profiler_;
int root_index_; HeapEntry* root_entry_ = nullptr;
int gc_roots_index_; HeapEntry* gc_roots_entry_ = nullptr;
int gc_subroot_indexes_[static_cast<int>(Root::kNumberOfRoots)]; HeapEntry* gc_subroot_entries_[static_cast<int>(Root::kNumberOfRoots)];
std::vector<HeapEntry> entries_; // 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> edges_;
std::deque<HeapGraphEdge*> children_; std::vector<HeapGraphEdge*> children_;
std::vector<HeapEntry*> sorted_entries_; std::unordered_map<SnapshotObjectId, HeapEntry*> entries_by_id_cache_;
std::vector<SourceLocation> locations_; std::vector<SourceLocation> locations_;
SnapshotObjectId max_snapshot_js_object_id_; SnapshotObjectId max_snapshot_js_object_id_ = -1;
friend class HeapSnapshotTester;
DISALLOW_COPY_AND_ASSIGN(HeapSnapshot); DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
}; };
@ -341,93 +334,81 @@ class V8HeapExplorer : public HeapEntriesAllocator {
const char* GetSystemEntryName(HeapObject* object); const char* GetSystemEntryName(HeapObject* object);
void ExtractLocation(int entry, HeapObject* object); void ExtractLocation(HeapEntry* entry, HeapObject* object);
void ExtractLocationForJSFunction(int entry, JSFunction* func); void ExtractLocationForJSFunction(HeapEntry* entry, JSFunction* func);
void ExtractReferences(int entry, HeapObject* obj); void ExtractReferences(HeapEntry* entry, HeapObject* obj);
void ExtractJSGlobalProxyReferences(int entry, JSGlobalProxy* proxy); void ExtractJSGlobalProxyReferences(HeapEntry* entry, JSGlobalProxy* proxy);
void ExtractJSObjectReferences(int entry, JSObject* js_obj); void ExtractJSObjectReferences(HeapEntry* entry, JSObject* js_obj);
void ExtractStringReferences(int entry, String* obj); void ExtractStringReferences(HeapEntry* entry, String* obj);
void ExtractSymbolReferences(int entry, Symbol* symbol); void ExtractSymbolReferences(HeapEntry* entry, Symbol* symbol);
void ExtractJSCollectionReferences(int entry, JSCollection* collection); void ExtractJSCollectionReferences(HeapEntry* entry,
void ExtractJSWeakCollectionReferences(int entry, JSCollection* collection);
void ExtractJSWeakCollectionReferences(HeapEntry* entry,
JSWeakCollection* collection); JSWeakCollection* collection);
void ExtractEphemeronHashTableReferences(int entry, void ExtractEphemeronHashTableReferences(HeapEntry* entry,
EphemeronHashTable* table); EphemeronHashTable* table);
void ExtractContextReferences(int entry, Context* context); void ExtractContextReferences(HeapEntry* entry, Context* context);
void ExtractMapReferences(int entry, Map* map); void ExtractMapReferences(HeapEntry* entry, Map* map);
void ExtractSharedFunctionInfoReferences(int entry, void ExtractSharedFunctionInfoReferences(HeapEntry* entry,
SharedFunctionInfo* shared); SharedFunctionInfo* shared);
void ExtractScriptReferences(int entry, Script* script); void ExtractScriptReferences(HeapEntry* entry, Script* script);
void ExtractAccessorInfoReferences(int entry, AccessorInfo* accessor_info); void ExtractAccessorInfoReferences(HeapEntry* entry,
void ExtractAccessorPairReferences(int entry, AccessorPair* accessors); AccessorInfo* accessor_info);
void ExtractCodeReferences(int entry, Code* code); void ExtractAccessorPairReferences(HeapEntry* entry, AccessorPair* accessors);
void ExtractCellReferences(int entry, Cell* cell); void ExtractCodeReferences(HeapEntry* entry, Code* code);
void ExtractFeedbackCellReferences(int entry, FeedbackCell* feedback_cell); void ExtractCellReferences(HeapEntry* entry, Cell* cell);
void ExtractPropertyCellReferences(int entry, PropertyCell* cell); void ExtractFeedbackCellReferences(HeapEntry* entry,
void ExtractAllocationSiteReferences(int entry, AllocationSite* site); FeedbackCell* feedback_cell);
void ExtractPropertyCellReferences(HeapEntry* entry, PropertyCell* cell);
void ExtractAllocationSiteReferences(HeapEntry* entry, AllocationSite* site);
void ExtractArrayBoilerplateDescriptionReferences( void ExtractArrayBoilerplateDescriptionReferences(
int entry, ArrayBoilerplateDescription* value); HeapEntry* entry, ArrayBoilerplateDescription* value);
void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer); void ExtractJSArrayBufferReferences(HeapEntry* entry, JSArrayBuffer* buffer);
void ExtractJSPromiseReferences(int entry, JSPromise* promise); void ExtractJSPromiseReferences(HeapEntry* entry, JSPromise* promise);
void ExtractJSGeneratorObjectReferences(int entry, void ExtractJSGeneratorObjectReferences(HeapEntry* entry,
JSGeneratorObject* generator); JSGeneratorObject* generator);
void ExtractFixedArrayReferences(int entry, FixedArray* array); void ExtractFixedArrayReferences(HeapEntry* entry, FixedArray* array);
void ExtractFeedbackVectorReferences(int entry, void ExtractFeedbackVectorReferences(HeapEntry* entry,
FeedbackVector* feedback_vector); FeedbackVector* feedback_vector);
template <typename T> template <typename T>
void ExtractWeakArrayReferences(int header_size, int entry, T* array); void ExtractWeakArrayReferences(int header_size, HeapEntry* entry, T* array);
void ExtractPropertyReferences(JSObject* js_obj, int entry); void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractAccessorPairProperty(JSObject* js_obj, int entry, Name* key, void ExtractAccessorPairProperty(JSObject* js_obj, HeapEntry* entry,
Object* callback_obj, int field_offset = -1); Name* key, Object* callback_obj,
void ExtractElementReferences(JSObject* js_obj, int entry); int field_offset = -1);
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 IsEssentialObject(Object* object);
bool IsEssentialHiddenReference(Object* parent, int field_offset); bool IsEssentialHiddenReference(Object* parent, int field_offset);
void SetContextReference(HeapObject* parent_obj, void SetContextReference(HeapObject* parent_obj, HeapEntry* parent_entry,
int parent, String* reference_name, Object* child,
String* reference_name,
Object* child,
int field_offset); int field_offset);
void SetNativeBindReference(HeapObject* parent_obj, void SetNativeBindReference(HeapObject* parent_obj, HeapEntry* parent_entry,
int parent, const char* reference_name, Object* child);
const char* reference_name, void SetElementReference(HeapObject* parent_obj, HeapEntry* parent_entry,
Object* child); int index, Object* child);
void SetElementReference(HeapObject* parent_obj, void SetInternalReference(HeapObject* parent_obj, HeapEntry* parent_entry,
int parent, const char* reference_name, Object* child,
int index,
Object* child);
void SetInternalReference(HeapObject* parent_obj,
int parent,
const char* reference_name,
Object* child,
int field_offset = -1); int field_offset = -1);
void SetInternalReference(HeapObject* parent_obj, void SetInternalReference(HeapObject* parent_obj, HeapEntry* parent_entry,
int parent, int index, Object* child, int field_offset = -1);
int index, void SetHiddenReference(HeapObject* parent_obj, HeapEntry* parent_entry,
Object* child, int index, Object* child, int field_offset);
int field_offset = -1); void SetWeakReference(HeapObject* parent_obj, HeapEntry* parent_entry,
void SetHiddenReference(HeapObject* parent_obj, int parent, int index, const char* reference_name, Object* child_obj,
Object* child, int field_offset);
void SetWeakReference(HeapObject* parent_obj,
int parent,
const char* reference_name,
Object* child_obj,
int field_offset); int field_offset);
void SetWeakReference(HeapObject* parent_obj, void SetWeakReference(HeapObject* parent_obj, HeapEntry* parent_entry,
int parent, int index, Object* child_obj, int field_offset);
int index, void SetPropertyReference(HeapObject* parent_obj, HeapEntry* parent_entry,
Object* child_obj,
int field_offset);
void SetPropertyReference(HeapObject* parent_obj, int parent,
Name* reference_name, Object* child, Name* reference_name, Object* child,
const char* name_format_string = nullptr, const char* name_format_string = nullptr,
int field_offset = -1); int field_offset = -1);
void SetDataOrAccessorPropertyReference( void SetDataOrAccessorPropertyReference(
PropertyKind kind, JSObject* parent_obj, int parent, Name* reference_name, PropertyKind kind, JSObject* parent_obj, HeapEntry* parent_entry,
Object* child, const char* name_format_string = nullptr, Name* reference_name, Object* child,
int field_offset = -1); const char* name_format_string = nullptr, int field_offset = -1);
void SetUserGlobalReference(Object* user_global); void SetUserGlobalReference(Object* user_global);
void SetRootGcRootsReference(); void SetRootGcRootsReference();
@ -528,7 +509,7 @@ class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
public: public:
// The HeapEntriesMap instance is used to track a mapping between // The HeapEntriesMap instance is used to track a mapping between
// real heap objects and their representations in heap snapshots. // real heap objects and their representations in heap snapshots.
using HeapEntriesMap = std::unordered_map<HeapThing, int>; using HeapEntriesMap = std::unordered_map<HeapThing, HeapEntry*>;
HeapSnapshotGenerator(HeapSnapshot* snapshot, HeapSnapshotGenerator(HeapSnapshot* snapshot,
v8::ActivityControl* control, v8::ActivityControl* control,

View File

@ -157,12 +157,9 @@ static Optional<SourceLocation> GetLocation(const v8::HeapSnapshot* s,
const v8::HeapGraphNode* node) { const v8::HeapGraphNode* node) {
const i::HeapSnapshot* snapshot = reinterpret_cast<const i::HeapSnapshot*>(s); const i::HeapSnapshot* snapshot = reinterpret_cast<const i::HeapSnapshot*>(s);
const std::vector<SourceLocation>& locations = snapshot->locations(); const std::vector<SourceLocation>& locations = snapshot->locations();
const int index = const i::HeapEntry* entry = reinterpret_cast<const i::HeapEntry*>(node);
const_cast<i::HeapEntry*>(reinterpret_cast<const i::HeapEntry*>(node))
->index();
for (const auto& loc : locations) { for (const auto& loc : locations) {
if (loc.entry_index == index) { if (loc.entry_index == entry->index()) {
return Optional<SourceLocation>(loc); return Optional<SourceLocation>(loc);
} }
} }
@ -223,7 +220,7 @@ static bool ValidateSnapshot(const v8::HeapSnapshot* snapshot, int depth = 3) {
entry->value = reinterpret_cast<void*>(ref_count + 1); entry->value = reinterpret_cast<void*>(ref_count + 1);
} }
uint32_t unretained_entries_count = 0; uint32_t unretained_entries_count = 0;
std::vector<i::HeapEntry>& entries = heap_snapshot->entries(); std::deque<i::HeapEntry>& entries = heap_snapshot->entries();
for (i::HeapEntry& entry : entries) { for (i::HeapEntry& entry : entries) {
v8::base::HashMap::Entry* map_entry = visited.Lookup( v8::base::HashMap::Entry* map_entry = visited.Lookup(
reinterpret_cast<void*>(&entry), reinterpret_cast<void*>(&entry),
@ -1003,21 +1000,6 @@ TEST(HeapEntryIdsAndGC) {
CHECK_EQ(b1->GetId(), b2->GetId()); 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<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
snapshot))->GetSortedEntriesList();
const v8::HeapGraphNode* root2 = snapshot->GetRoot();
CHECK_EQ(root1, root2);
}
namespace { namespace {
class TestJSONStream : public v8::OutputStream { class TestJSONStream : public v8::OutputStream {