Commit a87b0e63 authored by Alexei Filippov's avatar Alexei Filippov Committed by Commit Bot

Revert "[heap profiler] Refactor: Replace indices with HeapEntry*"

This reverts commit 69a502ce.

Reason for revert: Broke the build https://ci.chromium.org/p/v8/builders/luci.v8.ci/V8%20Linux%20gcc%204.8/22123

Original change's description:
> [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}

TBR=ulan@chromium.org,alph@chromium.org,mlippautz@chromium.org

Change-Id: Ib4495f17a653a95f8d5af634da74905c63048f8e
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/1246235Reviewed-by: 's avatarAlexei Filippov <alph@chromium.org>
Commit-Queue: Alexei Filippov <alph@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56248}
parent f5e65cc8
...@@ -13,41 +13,51 @@ ...@@ -13,41 +13,51 @@
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) {
// Note: children_count_ and children_end_index_ are parts of a union. children_index_ = index;
int next_index = index + children_count_; int next_index = index + children_count_;
children_end_index_ = index; children_count_ = 0;
return next_index; return next_index;
} }
void HeapEntry::add_child(HeapGraphEdge* edge) { void HeapEntry::add_child(HeapGraphEdge* edge) {
snapshot_->children()[children_end_index_++] = edge; *(children_begin() + children_count_++) = edge;
} }
HeapGraphEdge* HeapEntry::child(int i) { return children_begin()[i]; } HeapGraphEdge* HeapEntry::child(int i) { return *(children_begin() + i); }
std::vector<HeapGraphEdge*>::iterator HeapEntry::children_begin() const {
return index_ == 0 ? snapshot_->children().begin()
: snapshot_->entries()[index_ - 1].children_end();
}
std::vector<HeapGraphEdge*>::iterator HeapEntry::children_end() const { std::deque<HeapGraphEdge*>::iterator HeapEntry::children_begin() {
DCHECK_GE(children_end_index_, 0); DCHECK_GE(children_index_, 0);
return snapshot_->children().begin() + children_end_index_; SLOW_DCHECK(
children_index_ < static_cast<int>(snapshot_->children().size()) ||
(children_index_ == static_cast<int>(snapshot_->children().size()) &&
children_count_ == 0));
return snapshot_->children().begin() + children_index_;
} }
int HeapEntry::children_count() const { std::deque<HeapGraphEdge*>::iterator HeapEntry::children_end() {
return static_cast<int>(children_end() - children_begin()); return children_begin() + children_count_;
} }
Isolate* HeapEntry::isolate() const { return snapshot_->profiler()->isolate(); } Isolate* HeapEntry::isolate() const { return snapshot_->profiler()->isolate(); }
......
...@@ -33,11 +33,10 @@ ...@@ -33,11 +33,10 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
HeapGraphEdge::HeapGraphEdge(Type type, const char* name, HeapEntry* from,
HeapEntry* to) HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to)
: bit_field_(TypeField::encode(type) | : bit_field_(TypeField::encode(type) | FromIndexField::encode(from)),
FromIndexField::encode(from->index())), to_index_(to),
to_entry_(to),
name_(name) { name_(name) {
DCHECK(type == kContextVariable DCHECK(type == kContextVariable
|| type == kProperty || type == kProperty
...@@ -46,42 +45,56 @@ HeapGraphEdge::HeapGraphEdge(Type type, const char* name, HeapEntry* from, ...@@ -46,42 +45,56 @@ HeapGraphEdge::HeapGraphEdge(Type type, const char* name, HeapEntry* from,
|| type == kWeak); || type == kWeak);
} }
HeapGraphEdge::HeapGraphEdge(Type type, int index, HeapEntry* from,
HeapEntry* to) HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to)
: bit_field_(TypeField::encode(type) | : bit_field_(TypeField::encode(type) | FromIndexField::encode(from)),
FromIndexField::encode(from->index())), to_index_(to),
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,
const char* name, SnapshotObjectId id, size_t self_size, 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,
unsigned trace_node_id) unsigned trace_node_id)
: type_(type), : type_(type),
index_(index), children_count_(0),
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()));
...@@ -163,24 +176,34 @@ const char* HeapEntry::TypeAsString() { ...@@ -163,24 +176,34 @@ 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)));
memset(&gc_subroot_entries_, 0, sizeof(gc_subroot_entries_)); for (int i = 0; i < static_cast<int>(Root::kNumberOfRoots); ++i) {
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();
...@@ -192,30 +215,42 @@ void HeapSnapshot::AddSyntheticRootEntries() { ...@@ -192,30 +215,42 @@ void HeapSnapshot::AddSyntheticRootEntries() {
DCHECK_EQ(HeapObjectsMap::kFirstAvailableObjectId, id); DCHECK_EQ(HeapObjectsMap::kFirstAvailableObjectId, id);
} }
void HeapSnapshot::AddRootEntry() {
DCHECK_NULL(root_entry_);
DCHECK(entries_.empty()); // Root entry must be the first one.
root_entry_ = AddEntry(HeapEntry::kSynthetic, "",
HeapObjectsMap::kInternalRootObjectId, 0, 0);
DCHECK_EQ(1u, entries_.size());
DCHECK_EQ(root_entry_, &entries_.front());
}
void HeapSnapshot::AddGcRootsEntry() {
DCHECK_NULL(gc_roots_entry_);
gc_roots_entry_ = AddEntry(HeapEntry::kSynthetic, "(GC roots)",
HeapObjectsMap::kGcRootsObjectId, 0, 0);
}
void HeapSnapshot::AddGcSubrootEntry(Root root, SnapshotObjectId id) { HeapEntry* HeapSnapshot::AddRootEntry() {
DCHECK_NULL(gc_subroot_entries_[static_cast<int>(root)]); DCHECK_EQ(root_index_, HeapEntry::kNoEntry);
gc_subroot_entries_[static_cast<int>(root)] = DCHECK(entries_.empty()); // Root entry must be the first one.
HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
"",
HeapObjectsMap::kInternalRootObjectId,
0,
0);
root_index_ = entry->index();
DCHECK_EQ(root_index_, 0);
return entry;
}
HeapEntry* HeapSnapshot::AddGcRootsEntry() {
DCHECK_EQ(gc_roots_index_, HeapEntry::kNoEntry);
HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
"(GC roots)",
HeapObjectsMap::kGcRootsObjectId,
0,
0);
gc_roots_index_ = entry->index();
return entry;
}
HeapEntry* HeapSnapshot::AddGcSubrootEntry(Root root, SnapshotObjectId id) {
DCHECK_EQ(gc_subroot_indexes_[static_cast<int>(root)], HeapEntry::kNoEntry);
HeapEntry* entry =
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(HeapEntry* entry, int scriptId, int line, void HeapSnapshot::AddLocation(int entry, int scriptId, int line, int col) {
int col) { locations_.emplace_back(entry, scriptId, line, col);
locations_.emplace_back(entry->index(), scriptId, line, col);
} }
HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
...@@ -223,35 +258,52 @@ HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, ...@@ -223,35 +258,52 @@ 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(!is_complete()); DCHECK(sorted_entries_.empty());
entries_.emplace_back(this, static_cast<int>(entries_.size()), type, name, id, entries_.emplace_back(this, type, name, id, size, trace_node_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) {
if (entries_by_id_cache_.empty()) { std::vector<HeapEntry*>* entries_by_id = GetSortedEntriesList();
CHECK(is_complete());
entries_by_id_cache_.reserve(entries_.size()); auto it = std::lower_bound(
entries_by_id->begin(), entries_by_id->end(), id,
[](HeapEntry* first, SnapshotObjectId val) { return first->id() < val; });
if (it == entries_by_id->end() || (*it)->id() != id) return nullptr;
return *it;
}
struct SortByIds {
bool operator()(const HeapEntry* entry1_ptr, const HeapEntry* entry2_ptr) {
return entry1_ptr->id() < entry2_ptr->id();
}
};
std::vector<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() {
if (sorted_entries_.empty()) {
sorted_entries_.reserve(entries_.size());
for (HeapEntry& entry : entries_) { for (HeapEntry& entry : entries_) {
entries_by_id_cache_.emplace(entry.id(), &entry); sorted_entries_.push_back(&entry);
} }
std::sort(sorted_entries_.begin(), sorted_entries_.end(), SortByIds());
} }
auto it = entries_by_id_cache_.find(id); return &sorted_entries_;
return it != entries_by_id_cache_.end() ? it->second : nullptr;
} }
void HeapSnapshot::Print(int max_depth) { void HeapSnapshot::Print(int max_depth) {
...@@ -503,7 +555,7 @@ HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) { ...@@ -503,7 +555,7 @@ HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) {
return AddEntry(reinterpret_cast<HeapObject*>(ptr)); return AddEntry(reinterpret_cast<HeapObject*>(ptr));
} }
void V8HeapExplorer::ExtractLocation(HeapEntry* entry, HeapObject* object) { void V8HeapExplorer::ExtractLocation(int 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);
...@@ -521,8 +573,7 @@ void V8HeapExplorer::ExtractLocation(HeapEntry* entry, HeapObject* object) { ...@@ -521,8 +573,7 @@ void V8HeapExplorer::ExtractLocation(HeapEntry* entry, HeapObject* object) {
} }
} }
void V8HeapExplorer::ExtractLocationForJSFunction(HeapEntry* entry, void V8HeapExplorer::ExtractLocationForJSFunction(int entry, JSFunction* func) {
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();
...@@ -625,20 +676,25 @@ HeapEntry* V8HeapExplorer::AddEntry(Address address, ...@@ -625,20 +676,25 @@ 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)
: names_(snapshot->profiler()->names()), entries_map_(entries_map) {} : snapshot_(snapshot),
names_(snapshot->profiler()->names()),
entries_map_(entries_map) {}
HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
return entries_map_->emplace(ptr, allocator->AllocateEntry(ptr)) HeapEntry* entry = allocator->AllocateEntry(ptr);
.first->second; entries_map_->emplace(ptr, entry->index());
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() ? it->second : nullptr; return it != entries_map_->end() ? &snapshot_->entries()[it->second]
: nullptr;
} }
HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
...@@ -646,32 +702,43 @@ class SnapshotFiller { ...@@ -646,32 +702,43 @@ class SnapshotFiller {
return entry != nullptr ? entry : AddEntry(ptr, allocator); return entry != nullptr ? entry : AddEntry(ptr, allocator);
} }
void SetIndexedReference(HeapGraphEdge::Type type, HeapEntry* parent, void SetIndexedReference(HeapGraphEdge::Type type,
int index, HeapEntry* child) { int parent,
parent->SetIndexedReference(type, index, child); int index,
HeapEntry* child_entry) {
HeapEntry* parent_entry = &snapshot_->entries()[parent];
parent_entry->SetIndexedReference(type, index, child_entry);
} }
void SetIndexedAutoIndexReference(HeapGraphEdge::Type type, HeapEntry* parent, void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
HeapEntry* child) { int parent,
int index = parent->children_count() + 1; HeapEntry* child_entry) {
parent->SetIndexedReference(type, index, child); HeapEntry* parent_entry = &snapshot_->entries()[parent];
int index = parent_entry->children_count() + 1;
parent_entry->SetIndexedReference(type, index, child_entry);
} }
void SetNamedReference(HeapGraphEdge::Type type, HeapEntry* parent, void SetNamedReference(HeapGraphEdge::Type type,
const char* reference_name, HeapEntry* child) { int parent,
parent->SetNamedReference(type, reference_name, child); const char* reference_name,
HeapEntry* child_entry) {
HeapEntry* parent_entry = &snapshot_->entries()[parent];
parent_entry->SetNamedReference(type, reference_name, child_entry);
} }
void SetNamedAutoIndexReference(HeapGraphEdge::Type type, HeapEntry* parent, void SetNamedAutoIndexReference(HeapGraphEdge::Type type, int parent,
const char* description, HeapEntry* child) { const char* description,
int index = parent->children_count() + 1; HeapEntry* child_entry) {
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->SetNamedReference(type, name, child); parent_entry->SetNamedReference(type, name, child_entry);
} }
private: private:
HeapSnapshot* snapshot_;
StringsStorage* names_; StringsStorage* names_;
HeapSnapshotGenerator::HeapEntriesMap* entries_map_; HeapSnapshotGenerator::HeapEntriesMap* entries_map_;
}; };
...@@ -711,7 +778,7 @@ int V8HeapExplorer::EstimateObjectsCount() { ...@@ -711,7 +778,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,
HeapEntry* parent) int 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)),
...@@ -750,10 +817,10 @@ class IndexedReferencesExtractor : public ObjectVisitor { ...@@ -750,10 +817,10 @@ class IndexedReferencesExtractor : public ObjectVisitor {
HeapObject* parent_obj_; HeapObject* parent_obj_;
Object** parent_start_; Object** parent_start_;
Object** parent_end_; Object** parent_end_;
HeapEntry* parent_; int parent_;
}; };
void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject* obj) { void V8HeapExplorer::ExtractReferences(int 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()) {
...@@ -817,15 +884,17 @@ void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject* obj) { ...@@ -817,15 +884,17 @@ void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject* obj) {
} }
} }
void V8HeapExplorer::ExtractJSGlobalProxyReferences(HeapEntry* entry,
JSGlobalProxy* proxy) { void V8HeapExplorer::ExtractJSGlobalProxyReferences(
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,
JSObject* js_obj) { void V8HeapExplorer::ExtractJSObjectReferences(
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);
...@@ -908,7 +977,8 @@ void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry, ...@@ -908,7 +977,8 @@ void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry,
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(),
...@@ -926,26 +996,28 @@ void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, String* string) { ...@@ -926,26 +996,28 @@ void V8HeapExplorer::ExtractStringReferences(HeapEntry* 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(HeapEntry* entry, void V8HeapExplorer::ExtractJSWeakCollectionReferences(int 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(
HeapEntry* entry, EphemeronHashTable* table) { int 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;
...@@ -957,18 +1029,18 @@ void V8HeapExplorer::ExtractEphemeronHashTableReferences( ...@@ -957,18 +1029,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(HeapGraphEdge::kInternal, key_entry, filler_->SetNamedAutoIndexReference(
edge_name, value_entry); HeapGraphEdge::kInternal, key_entry_index, edge_name, value_entry);
} }
} }
} }
void V8HeapExplorer::ExtractContextReferences(HeapEntry* entry, void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
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.
...@@ -1017,7 +1089,8 @@ void V8HeapExplorer::ExtractContextReferences(HeapEntry* entry, ...@@ -1017,7 +1089,8 @@ void V8HeapExplorer::ExtractContextReferences(HeapEntry* entry,
} }
} }
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(
...@@ -1081,8 +1154,9 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) { ...@@ -1081,8 +1154,9 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) {
Map::kDependentCodeOffset); Map::kDependentCodeOffset);
} }
void V8HeapExplorer::ExtractSharedFunctionInfoReferences( void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
HeapEntry* entry, SharedFunctionInfo* shared) { int 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;
...@@ -1113,7 +1187,7 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences( ...@@ -1113,7 +1187,7 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset); SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset);
} }
void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) { void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) {
HeapObject* obj = script; HeapObject* obj = script;
SetInternalReference(obj, entry, SetInternalReference(obj, entry,
"source", script->source(), "source", script->source(),
...@@ -1130,8 +1204,9 @@ void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) { ...@@ -1130,8 +1204,9 @@ void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) {
Script::kLineEndsOffset); Script::kLineEndsOffset);
} }
void V8HeapExplorer::ExtractAccessorInfoReferences( void V8HeapExplorer::ExtractAccessorInfoReferences(
HeapEntry* entry, AccessorInfo* accessor_info) { int 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",
...@@ -1145,8 +1220,8 @@ void V8HeapExplorer::ExtractAccessorInfoReferences( ...@@ -1145,8 +1220,8 @@ void V8HeapExplorer::ExtractAccessorInfoReferences(
AccessorInfo::kDataOffset); AccessorInfo::kDataOffset);
} }
void V8HeapExplorer::ExtractAccessorPairReferences(HeapEntry* entry, void V8HeapExplorer::ExtractAccessorPairReferences(
AccessorPair* accessors) { int entry, 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(),
...@@ -1165,7 +1240,7 @@ void V8HeapExplorer::TagCodeObject(Code* code) { ...@@ -1165,7 +1240,7 @@ void V8HeapExplorer::TagCodeObject(Code* code) {
} }
} }
void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code* code) { void V8HeapExplorer::ExtractCodeReferences(int 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,
...@@ -1181,18 +1256,18 @@ void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code* code) { ...@@ -1181,18 +1256,18 @@ void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code* code) {
Code::kSourcePositionTableOffset); Code::kSourcePositionTableOffset);
} }
void V8HeapExplorer::ExtractCellReferences(HeapEntry* entry, Cell* cell) { void V8HeapExplorer::ExtractCellReferences(int 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(
HeapEntry* entry, FeedbackCell* feedback_cell) { int 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(HeapEntry* entry, void V8HeapExplorer::ExtractPropertyCellReferences(int entry,
PropertyCell* cell) { PropertyCell* cell) {
SetInternalReference(cell, entry, "value", cell->value(), SetInternalReference(cell, entry, "value", cell->value(),
PropertyCell::kValueOffset); PropertyCell::kValueOffset);
...@@ -1201,7 +1276,7 @@ void V8HeapExplorer::ExtractPropertyCellReferences(HeapEntry* entry, ...@@ -1201,7 +1276,7 @@ void V8HeapExplorer::ExtractPropertyCellReferences(HeapEntry* entry,
PropertyCell::kDependentCodeOffset); PropertyCell::kDependentCodeOffset);
} }
void V8HeapExplorer::ExtractAllocationSiteReferences(HeapEntry* entry, void V8HeapExplorer::ExtractAllocationSiteReferences(int 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(),
...@@ -1214,7 +1289,7 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(HeapEntry* entry, ...@@ -1214,7 +1289,7 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(HeapEntry* entry,
} }
void V8HeapExplorer::ExtractArrayBoilerplateDescriptionReferences( void V8HeapExplorer::ExtractArrayBoilerplateDescriptionReferences(
HeapEntry* entry, ArrayBoilerplateDescription* value) { int entry, ArrayBoilerplateDescription* value) {
SetInternalReference(value, entry, "constant_elements", SetInternalReference(value, entry, "constant_elements",
value->constant_elements(), value->constant_elements(),
ArrayBoilerplateDescription::kConstantElementsOffset); ArrayBoilerplateDescription::kConstantElementsOffset);
...@@ -1236,8 +1311,8 @@ class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator { ...@@ -1236,8 +1311,8 @@ class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator {
V8HeapExplorer* explorer_; V8HeapExplorer* explorer_;
}; };
void V8HeapExplorer::ExtractJSArrayBufferReferences(HeapEntry* entry, void V8HeapExplorer::ExtractJSArrayBufferReferences(
JSArrayBuffer* buffer) { int entry, 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;
...@@ -1249,15 +1324,14 @@ void V8HeapExplorer::ExtractJSArrayBufferReferences(HeapEntry* entry, ...@@ -1249,15 +1324,14 @@ void V8HeapExplorer::ExtractJSArrayBufferReferences(HeapEntry* entry,
entry, "backing_store", data_entry); entry, "backing_store", data_entry);
} }
void V8HeapExplorer::ExtractJSPromiseReferences(HeapEntry* entry, void V8HeapExplorer::ExtractJSPromiseReferences(int entry, JSPromise* promise) {
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(
HeapEntry* entry, JSGeneratorObject* generator) { int 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(),
...@@ -1269,8 +1343,7 @@ void V8HeapExplorer::ExtractJSGeneratorObjectReferences( ...@@ -1269,8 +1343,7 @@ void V8HeapExplorer::ExtractJSGeneratorObjectReferences(
JSGeneratorObject::kParametersAndRegistersOffset); JSGeneratorObject::kParametersAndRegistersOffset);
} }
void V8HeapExplorer::ExtractFixedArrayReferences(HeapEntry* entry, void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) {
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),
...@@ -1279,7 +1352,7 @@ void V8HeapExplorer::ExtractFixedArrayReferences(HeapEntry* entry, ...@@ -1279,7 +1352,7 @@ void V8HeapExplorer::ExtractFixedArrayReferences(HeapEntry* entry,
} }
void V8HeapExplorer::ExtractFeedbackVectorReferences( void V8HeapExplorer::ExtractFeedbackVectorReferences(
HeapEntry* entry, FeedbackVector* feedback_vector) { int 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)) {
...@@ -1289,8 +1362,8 @@ void V8HeapExplorer::ExtractFeedbackVectorReferences( ...@@ -1289,8 +1362,8 @@ void V8HeapExplorer::ExtractFeedbackVectorReferences(
} }
template <typename T> template <typename T>
void V8HeapExplorer::ExtractWeakArrayReferences(int header_size, void V8HeapExplorer::ExtractWeakArrayReferences(int header_size, int entry,
HeapEntry* entry, T* array) { 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;
...@@ -1304,8 +1377,7 @@ void V8HeapExplorer::ExtractWeakArrayReferences(int header_size, ...@@ -1304,8 +1377,7 @@ void V8HeapExplorer::ExtractWeakArrayReferences(int header_size,
} }
} }
void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
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();
...@@ -1366,8 +1438,9 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, ...@@ -1366,8 +1438,9 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
} }
} }
void V8HeapExplorer::ExtractAccessorPairProperty(JSObject* js_obj,
HeapEntry* entry, Name* key, void V8HeapExplorer::ExtractAccessorPairProperty(JSObject* js_obj, int entry,
Name* key,
Object* callback_obj, Object* callback_obj,
int field_offset) { int field_offset) {
if (!callback_obj->IsAccessorPair()) return; if (!callback_obj->IsAccessorPair()) return;
...@@ -1383,8 +1456,8 @@ void V8HeapExplorer::ExtractAccessorPairProperty(JSObject* js_obj, ...@@ -1383,8 +1456,8 @@ void V8HeapExplorer::ExtractAccessorPairProperty(JSObject* js_obj,
} }
} }
void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj,
HeapEntry* entry) { void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int 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());
...@@ -1410,8 +1483,8 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, ...@@ -1410,8 +1483,8 @@ void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj,
} }
} }
void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj,
HeapEntry* entry) { void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, int 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);
...@@ -1506,7 +1579,8 @@ bool V8HeapExplorer::IterateAndExtractReferences(SnapshotFiller* filler) { ...@@ -1506,7 +1579,8 @@ bool V8HeapExplorer::IterateAndExtractReferences(SnapshotFiller* filler) {
visited_fields_.resize(max_pointer, false); visited_fields_.resize(max_pointer, false);
} }
HeapEntry* entry = GetEntry(obj); HeapEntry* heap_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
...@@ -1560,10 +1634,11 @@ bool V8HeapExplorer::IsEssentialHiddenReference(Object* parent, ...@@ -1560,10 +1634,11 @@ bool V8HeapExplorer::IsEssentialHiddenReference(Object* parent,
} }
void V8HeapExplorer::SetContextReference(HeapObject* parent_obj, void V8HeapExplorer::SetContextReference(HeapObject* parent_obj,
HeapEntry* parent_entry, int parent_entry,
String* reference_name, String* reference_name,
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;
filler_->SetNamedReference(HeapGraphEdge::kContextVariable, parent_entry, filler_->SetNamedReference(HeapGraphEdge::kContextVariable, parent_entry,
...@@ -1578,32 +1653,37 @@ void V8HeapExplorer::MarkVisitedField(int offset) { ...@@ -1578,32 +1653,37 @@ 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,
HeapEntry* parent_entry, int parent_entry,
const char* reference_name, const char* reference_name,
Object* child_obj) { Object* child_obj) {
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::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,
HeapEntry* parent_entry, int index, int parent_entry,
int index,
Object* child_obj) { Object* child_obj) {
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_->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,
HeapEntry* parent_entry, int parent_entry,
const char* reference_name, const char* reference_name,
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)) {
...@@ -1615,10 +1695,13 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, ...@@ -1615,10 +1695,13 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
MarkVisitedField(field_offset); MarkVisitedField(field_offset);
} }
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent_entry, int index, int parent_entry,
Object* child_obj, int field_offset) { int index,
DCHECK_EQ(parent_entry, GetEntry(parent_obj)); Object* child_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)) {
...@@ -1631,9 +1714,9 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, ...@@ -1631,9 +1714,9 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
} }
void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
HeapEntry* parent_entry, int index, int parent_entry, int index,
Object* child_obj, int field_offset) { Object* child_obj, 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 && IsEssentialObject(child_obj) && if (child_entry != nullptr && IsEssentialObject(child_obj) &&
IsEssentialHiddenReference(parent_obj, field_offset)) { IsEssentialHiddenReference(parent_obj, field_offset)) {
...@@ -1642,11 +1725,13 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, ...@@ -1642,11 +1725,13 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
} }
} }
void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
HeapEntry* parent_entry, int parent_entry,
const char* reference_name, const char* reference_name,
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)) {
...@@ -1658,10 +1743,13 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, ...@@ -1658,10 +1743,13 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
MarkVisitedField(field_offset); MarkVisitedField(field_offset);
} }
void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
HeapEntry* parent_entry, int index, int parent_entry,
Object* child_obj, int field_offset) { int index,
DCHECK_EQ(parent_entry, GetEntry(parent_obj)); Object* child_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)) {
...@@ -1674,10 +1762,9 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, ...@@ -1674,10 +1762,9 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
} }
void V8HeapExplorer::SetDataOrAccessorPropertyReference( void V8HeapExplorer::SetDataOrAccessorPropertyReference(
PropertyKind kind, JSObject* parent_obj, HeapEntry* parent_entry, PropertyKind kind, JSObject* parent_obj, int 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);
...@@ -1687,10 +1774,14 @@ void V8HeapExplorer::SetDataOrAccessorPropertyReference( ...@@ -1687,10 +1774,14 @@ void V8HeapExplorer::SetDataOrAccessorPropertyReference(
} }
} }
void V8HeapExplorer::SetPropertyReference(
HeapObject* parent_obj, HeapEntry* parent_entry, Name* reference_name, void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
Object* child_obj, const char* name_format_string, int field_offset) { int parent_entry,
DCHECK_EQ(parent_entry, GetEntry(parent_obj)); Name* reference_name,
Object* child_obj,
const char* name_format_string,
int field_offset) {
DCHECK(parent_entry == GetEntry(parent_obj)->index());
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry == nullptr) return; if (child_entry == nullptr) return;
HeapGraphEdge::Type type = HeapGraphEdge::Type type =
...@@ -1712,19 +1803,22 @@ void V8HeapExplorer::SetPropertyReference( ...@@ -1712,19 +1803,22 @@ void V8HeapExplorer::SetPropertyReference(
void V8HeapExplorer::SetRootGcRootsReference() { void V8HeapExplorer::SetRootGcRootsReference() {
filler_->SetIndexedAutoIndexReference( filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement, snapshot_->root(), snapshot_->gc_roots()); HeapGraphEdge::kElement,
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(), nullptr, child_entry); snapshot_->root()->index(), nullptr,
child_entry);
} }
void V8HeapExplorer::SetGcRootsReference(Root root) { void V8HeapExplorer::SetGcRootsReference(Root root) {
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
snapshot_->gc_roots(), snapshot_->gc_roots()->index(),
snapshot_->gc_subroot(root)); snapshot_->gc_subroot(root));
} }
...@@ -1736,10 +1830,11 @@ void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description, ...@@ -1736,10 +1830,11 @@ 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), name, filler_->SetNamedReference(edge_type, snapshot_->gc_subroot(root)->index(),
child_entry); name, child_entry);
} else { } else {
filler_->SetNamedAutoIndexReference(edge_type, snapshot_->gc_subroot(root), filler_->SetNamedAutoIndexReference(edge_type,
snapshot_->gc_subroot(root)->index(),
description, child_entry); description, child_entry);
} }
...@@ -2076,9 +2171,10 @@ void NativeObjectsExplorer::FillEdges() { ...@@ -2076,9 +2171,10 @@ 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);
HeapEntry* parent_entry = int parent_entry =
filler_->FindOrAddEntry(parent, native_entries_allocator_.get()); filler_->FindOrAddEntry(parent, native_entries_allocator_.get())
DCHECK_NOT_NULL(parent_entry); ->index();
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);
...@@ -2131,7 +2227,7 @@ bool NativeObjectsExplorer::IterateAndExtractReferences( ...@@ -2131,7 +2227,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(), HeapGraphEdge::kElement, snapshot_->root()->index(),
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.
...@@ -2150,14 +2246,17 @@ bool NativeObjectsExplorer::IterateAndExtractReferences( ...@@ -2150,14 +2246,17 @@ 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, from, filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
to); from_index, to);
} else { } else {
filler_->SetNamedReference(HeapGraphEdge::kInternal, from, edge.name, filler_->SetNamedReference(HeapGraphEdge::kInternal, from_index,
to); edge.name, to);
} }
} }
} }
...@@ -2198,8 +2297,11 @@ void NativeObjectsExplorer::SetNativeRootReference( ...@@ -2198,8 +2297,11 @@ 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());
filler_->SetNamedAutoIndexReference(HeapGraphEdge::kInternal, group_entry, // |FindOrAddEntry| can move and resize the entries backing store. Reload
nullptr, child_entry); // potentially-stale pointer.
child_entry = filler_->FindEntry(info);
filler_->SetNamedAutoIndexReference(
HeapGraphEdge::kInternal, group_entry->index(), nullptr, child_entry);
} }
...@@ -2210,9 +2312,12 @@ void NativeObjectsExplorer::SetWrapperNativeReferences( ...@@ -2210,9 +2312,12 @@ 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, wrapper_entry, "native", filler_->SetNamedReference(HeapGraphEdge::kInternal,
wrapper_entry->index(),
"native",
info_entry); info_entry);
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, info_entry, filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
info_entry->index(),
wrapper_entry); wrapper_entry);
} }
...@@ -2223,8 +2328,10 @@ void NativeObjectsExplorer::SetRootNativeRootsReference() { ...@@ -2223,8 +2328,10 @@ 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(HeapGraphEdge::kElement, filler_->SetIndexedAutoIndexReference(
snapshot_->root(), group_entry); HeapGraphEdge::kElement,
snapshot_->root()->index(),
group_entry);
} }
} }
...@@ -2571,8 +2678,9 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge, ...@@ -2571,8 +2678,9 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
writer_->AddString(buffer.start()); writer_->AddString(buffer.start());
} }
void HeapSnapshotJSONSerializer::SerializeEdges() { void HeapSnapshotJSONSerializer::SerializeEdges() {
std::vector<HeapGraphEdge*>& edges = snapshot_->children(); std::deque<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());
...@@ -2608,14 +2716,16 @@ void HeapSnapshotJSONSerializer::SerializeNode(const HeapEntry* entry) { ...@@ -2608,14 +2716,16 @@ void HeapSnapshotJSONSerializer::SerializeNode(const HeapEntry* entry) {
writer_->AddString(buffer.start()); writer_->AddString(buffer.start());
} }
void HeapSnapshotJSONSerializer::SerializeNodes() { void HeapSnapshotJSONSerializer::SerializeNodes() {
const std::deque<HeapEntry>& entries = snapshot_->entries(); std::vector<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.
......
...@@ -60,8 +60,9 @@ class HeapGraphEdge { ...@@ -60,8 +60,9 @@ class HeapGraphEdge {
kWeak = v8::HeapGraphEdge::kWeak kWeak = v8::HeapGraphEdge::kWeak
}; };
HeapGraphEdge(Type type, const char* name, HeapEntry* from, HeapEntry* to); HeapGraphEdge(Type type, const char* name, int from, int to);
HeapGraphEdge(Type type, int index, HeapEntry* from, HeapEntry* to); HeapGraphEdge(Type type, int index, int from, int 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 {
...@@ -85,7 +86,12 @@ class HeapGraphEdge { ...@@ -85,7 +86,12 @@ 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_;
HeapEntry* to_entry_; 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_;
};
union { union {
int index_; int index_;
const char* name_; const char* name_;
...@@ -113,9 +119,15 @@ class HeapEntry { ...@@ -113,9 +119,15 @@ class HeapEntry {
kSymbol = v8::HeapGraphNode::kSymbol, kSymbol = v8::HeapGraphNode::kSymbol,
kBigInt = v8::HeapGraphNode::kBigInt kBigInt = v8::HeapGraphNode::kBigInt
}; };
static const int kNoEntry;
HeapEntry(HeapSnapshot* snapshot, int index, Type type, const char* name, HeapEntry() = default;
SnapshotObjectId id, size_t self_size, unsigned trace_node_id); HeapEntry(HeapSnapshot* snapshot,
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_); }
...@@ -125,8 +137,8 @@ class HeapEntry { ...@@ -125,8 +137,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_; }
int index() const { return index_; } V8_INLINE int index() const;
V8_INLINE int children_count() const; int children_count() const { return children_count_; }
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);
...@@ -141,18 +153,13 @@ class HeapEntry { ...@@ -141,18 +153,13 @@ 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::vector<HeapGraphEdge*>::iterator children_begin() const; V8_INLINE std::deque<HeapGraphEdge*>::iterator children_begin();
V8_INLINE std::vector<HeapGraphEdge*>::iterator children_end() const; V8_INLINE std::deque<HeapGraphEdge*>::iterator children_end();
const char* TypeAsString(); const char* TypeAsString();
unsigned type_: 4; unsigned type_: 4;
unsigned index_ : 28; // Supports up to ~250M objects. int children_count_: 28;
union { int children_index_;
// 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_;
...@@ -161,6 +168,7 @@ class HeapEntry { ...@@ -161,6 +168,7 @@ 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
...@@ -171,23 +179,22 @@ class HeapSnapshot { ...@@ -171,23 +179,22 @@ class HeapSnapshot {
explicit HeapSnapshot(HeapProfiler* profiler); explicit HeapSnapshot(HeapProfiler* profiler);
void Delete(); void Delete();
HeapProfiler* profiler() const { return profiler_; } HeapProfiler* profiler() { return profiler_; }
HeapEntry* root() const { return root_entry_; } HeapEntry* root() { return &entries_[root_index_]; }
HeapEntry* gc_roots() const { return gc_roots_entry_; } HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; }
HeapEntry* gc_subroot(Root root) const { HeapEntry* gc_subroot(Root root) {
return gc_subroot_entries_[static_cast<int>(root)]; return &entries_[gc_subroot_indexes_[static_cast<int>(root)]];
} }
std::deque<HeapEntry>& entries() { return entries_; } std::vector<HeapEntry>& entries() { return entries_; }
std::deque<HeapGraphEdge>& edges() { return edges_; } std::deque<HeapGraphEdge>& edges() { return edges_; }
std::vector<HeapGraphEdge*>& children() { return children_; } std::deque<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(HeapEntry* entry, int scriptId, int line, int col); void AddLocation(int 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,
...@@ -195,28 +202,28 @@ class HeapSnapshot { ...@@ -195,28 +202,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:
void AddRootEntry(); HeapEntry* AddRootEntry();
void AddGcRootsEntry(); HeapEntry* AddGcRootsEntry();
void AddGcSubrootEntry(Root root, SnapshotObjectId id); HeapEntry* AddGcSubrootEntry(Root root, SnapshotObjectId id);
HeapProfiler* profiler_; HeapProfiler* profiler_;
HeapEntry* root_entry_ = nullptr; int root_index_;
HeapEntry* gc_roots_entry_ = nullptr; int gc_roots_index_;
HeapEntry* gc_subroot_entries_[static_cast<int>(Root::kNumberOfRoots)]; int gc_subroot_indexes_[static_cast<int>(Root::kNumberOfRoots)];
// For |entries_| we rely on the deque property, that it never reallocates std::vector<HeapEntry> entries_;
// 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::vector<HeapGraphEdge*> children_; std::deque<HeapGraphEdge*> children_;
std::unordered_map<SnapshotObjectId, HeapEntry*> entries_by_id_cache_; std::vector<HeapEntry*> sorted_entries_;
std::vector<SourceLocation> locations_; std::vector<SourceLocation> locations_;
SnapshotObjectId max_snapshot_js_object_id_ = -1; SnapshotObjectId max_snapshot_js_object_id_;
friend class HeapSnapshotTester;
DISALLOW_COPY_AND_ASSIGN(HeapSnapshot); DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
}; };
...@@ -334,81 +341,93 @@ class V8HeapExplorer : public HeapEntriesAllocator { ...@@ -334,81 +341,93 @@ class V8HeapExplorer : public HeapEntriesAllocator {
const char* GetSystemEntryName(HeapObject* object); const char* GetSystemEntryName(HeapObject* object);
void ExtractLocation(HeapEntry* entry, HeapObject* object); void ExtractLocation(int entry, HeapObject* object);
void ExtractLocationForJSFunction(HeapEntry* entry, JSFunction* func); void ExtractLocationForJSFunction(int entry, JSFunction* func);
void ExtractReferences(HeapEntry* entry, HeapObject* obj); void ExtractReferences(int entry, HeapObject* obj);
void ExtractJSGlobalProxyReferences(HeapEntry* entry, JSGlobalProxy* proxy); void ExtractJSGlobalProxyReferences(int entry, JSGlobalProxy* proxy);
void ExtractJSObjectReferences(HeapEntry* entry, JSObject* js_obj); void ExtractJSObjectReferences(int entry, JSObject* js_obj);
void ExtractStringReferences(HeapEntry* entry, String* obj); void ExtractStringReferences(int entry, String* obj);
void ExtractSymbolReferences(HeapEntry* entry, Symbol* symbol); void ExtractSymbolReferences(int entry, Symbol* symbol);
void ExtractJSCollectionReferences(HeapEntry* entry, void ExtractJSCollectionReferences(int entry, JSCollection* collection);
JSCollection* collection); void ExtractJSWeakCollectionReferences(int entry,
void ExtractJSWeakCollectionReferences(HeapEntry* entry,
JSWeakCollection* collection); JSWeakCollection* collection);
void ExtractEphemeronHashTableReferences(HeapEntry* entry, void ExtractEphemeronHashTableReferences(int entry,
EphemeronHashTable* table); EphemeronHashTable* table);
void ExtractContextReferences(HeapEntry* entry, Context* context); void ExtractContextReferences(int entry, Context* context);
void ExtractMapReferences(HeapEntry* entry, Map* map); void ExtractMapReferences(int entry, Map* map);
void ExtractSharedFunctionInfoReferences(HeapEntry* entry, void ExtractSharedFunctionInfoReferences(int entry,
SharedFunctionInfo* shared); SharedFunctionInfo* shared);
void ExtractScriptReferences(HeapEntry* entry, Script* script); void ExtractScriptReferences(int entry, Script* script);
void ExtractAccessorInfoReferences(HeapEntry* entry, void ExtractAccessorInfoReferences(int entry, AccessorInfo* accessor_info);
AccessorInfo* accessor_info); void ExtractAccessorPairReferences(int entry, AccessorPair* accessors);
void ExtractAccessorPairReferences(HeapEntry* entry, AccessorPair* accessors); void ExtractCodeReferences(int entry, Code* code);
void ExtractCodeReferences(HeapEntry* entry, Code* code); void ExtractCellReferences(int entry, Cell* cell);
void ExtractCellReferences(HeapEntry* entry, Cell* cell); void ExtractFeedbackCellReferences(int entry, FeedbackCell* feedback_cell);
void ExtractFeedbackCellReferences(HeapEntry* entry, void ExtractPropertyCellReferences(int entry, PropertyCell* cell);
FeedbackCell* feedback_cell); void ExtractAllocationSiteReferences(int entry, AllocationSite* site);
void ExtractPropertyCellReferences(HeapEntry* entry, PropertyCell* cell);
void ExtractAllocationSiteReferences(HeapEntry* entry, AllocationSite* site);
void ExtractArrayBoilerplateDescriptionReferences( void ExtractArrayBoilerplateDescriptionReferences(
HeapEntry* entry, ArrayBoilerplateDescription* value); int entry, ArrayBoilerplateDescription* value);
void ExtractJSArrayBufferReferences(HeapEntry* entry, JSArrayBuffer* buffer); void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer);
void ExtractJSPromiseReferences(HeapEntry* entry, JSPromise* promise); void ExtractJSPromiseReferences(int entry, JSPromise* promise);
void ExtractJSGeneratorObjectReferences(HeapEntry* entry, void ExtractJSGeneratorObjectReferences(int entry,
JSGeneratorObject* generator); JSGeneratorObject* generator);
void ExtractFixedArrayReferences(HeapEntry* entry, FixedArray* array); void ExtractFixedArrayReferences(int entry, FixedArray* array);
void ExtractFeedbackVectorReferences(HeapEntry* entry, void ExtractFeedbackVectorReferences(int entry,
FeedbackVector* feedback_vector); FeedbackVector* feedback_vector);
template <typename T> template <typename T>
void ExtractWeakArrayReferences(int header_size, HeapEntry* entry, T* array); void ExtractWeakArrayReferences(int header_size, int entry, T* array);
void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry); void ExtractPropertyReferences(JSObject* js_obj, int entry);
void ExtractAccessorPairProperty(JSObject* js_obj, HeapEntry* entry, void ExtractAccessorPairProperty(JSObject* js_obj, int entry, Name* key,
Name* key, Object* callback_obj, Object* callback_obj, int field_offset = -1);
int field_offset = -1); void ExtractElementReferences(JSObject* js_obj, int entry);
void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry); void ExtractInternalReferences(JSObject* js_obj, int 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, HeapEntry* parent_entry, void SetContextReference(HeapObject* parent_obj,
String* reference_name, Object* child, int parent,
String* reference_name,
Object* child,
int field_offset); int field_offset);
void SetNativeBindReference(HeapObject* parent_obj, HeapEntry* parent_entry, void SetNativeBindReference(HeapObject* parent_obj,
const char* reference_name, Object* child); int parent,
void SetElementReference(HeapObject* parent_obj, HeapEntry* parent_entry, const char* reference_name,
int index, Object* child); Object* child);
void SetInternalReference(HeapObject* parent_obj, HeapEntry* parent_entry, void SetElementReference(HeapObject* parent_obj,
const char* reference_name, Object* child, int parent,
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, HeapEntry* parent_entry, void SetInternalReference(HeapObject* parent_obj,
int index, Object* child, int field_offset = -1); int parent,
void SetHiddenReference(HeapObject* parent_obj, HeapEntry* parent_entry, int index,
int index, Object* child, int field_offset); Object* child,
void SetWeakReference(HeapObject* parent_obj, HeapEntry* parent_entry, int field_offset = -1);
const char* reference_name, Object* child_obj, 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,
int field_offset);
void SetWeakReference(HeapObject* parent_obj,
int parent,
int index,
Object* child_obj,
int field_offset); int field_offset);
void SetWeakReference(HeapObject* parent_obj, HeapEntry* parent_entry, void SetPropertyReference(HeapObject* parent_obj, int parent,
int index, Object* child_obj, int field_offset);
void SetPropertyReference(HeapObject* parent_obj, HeapEntry* parent_entry,
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, HeapEntry* parent_entry, PropertyKind kind, JSObject* parent_obj, int parent, Name* reference_name,
Name* reference_name, Object* child, Object* child, const char* name_format_string = nullptr,
const char* name_format_string = nullptr, int field_offset = -1); int field_offset = -1);
void SetUserGlobalReference(Object* user_global); void SetUserGlobalReference(Object* user_global);
void SetRootGcRootsReference(); void SetRootGcRootsReference();
...@@ -509,7 +528,7 @@ class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface { ...@@ -509,7 +528,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, HeapEntry*>; using HeapEntriesMap = std::unordered_map<HeapThing, int>;
HeapSnapshotGenerator(HeapSnapshot* snapshot, HeapSnapshotGenerator(HeapSnapshot* snapshot,
v8::ActivityControl* control, v8::ActivityControl* control,
......
...@@ -157,9 +157,12 @@ static Optional<SourceLocation> GetLocation(const v8::HeapSnapshot* s, ...@@ -157,9 +157,12 @@ 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 i::HeapEntry* entry = reinterpret_cast<const i::HeapEntry*>(node); const int index =
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 == entry->index()) { if (loc.entry_index == index) {
return Optional<SourceLocation>(loc); return Optional<SourceLocation>(loc);
} }
} }
...@@ -220,7 +223,7 @@ static bool ValidateSnapshot(const v8::HeapSnapshot* snapshot, int depth = 3) { ...@@ -220,7 +223,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::deque<i::HeapEntry>& entries = heap_snapshot->entries(); std::vector<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),
...@@ -1000,6 +1003,21 @@ TEST(HeapEntryIdsAndGC) { ...@@ -1000,6 +1003,21 @@ 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 {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment