[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:
parent
c86b90d12c
commit
69a502ce5c
@ -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(); }
|
||||||
|
@ -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.
|
||||||
|
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user