Revert "[heap profiler] Refactor: Replace indices with HeapEntry*"
This reverts commit 69a502ce5c
.
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/1246235
Reviewed-by: Alexei Filippov <alph@chromium.org>
Commit-Queue: Alexei Filippov <alph@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56248}
This commit is contained in:
parent
f5e65cc81d
commit
a87b0e63db
@ -13,41 +13,51 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
HeapEntry* HeapGraphEdge::from() const {
|
||||
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 {
|
||||
return to_entry_->snapshot();
|
||||
}
|
||||
|
||||
|
||||
int HeapEntry::index() const {
|
||||
return static_cast<int>(this - &snapshot_->entries().front());
|
||||
}
|
||||
|
||||
|
||||
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_;
|
||||
children_end_index_ = index;
|
||||
children_count_ = 0;
|
||||
return next_index;
|
||||
}
|
||||
|
||||
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::deque<HeapGraphEdge*>::iterator HeapEntry::children_begin() {
|
||||
DCHECK_GE(children_index_, 0);
|
||||
SLOW_DCHECK(
|
||||
children_index_ < static_cast<int>(snapshot_->children().size()) ||
|
||||
(children_index_ == static_cast<int>(snapshot_->children().size()) &&
|
||||
children_count_ == 0));
|
||||
return snapshot_->children().begin() + children_index_;
|
||||
}
|
||||
|
||||
std::vector<HeapGraphEdge*>::iterator HeapEntry::children_end() const {
|
||||
DCHECK_GE(children_end_index_, 0);
|
||||
return snapshot_->children().begin() + children_end_index_;
|
||||
}
|
||||
|
||||
int HeapEntry::children_count() const {
|
||||
return static_cast<int>(children_end() - children_begin());
|
||||
std::deque<HeapGraphEdge*>::iterator HeapEntry::children_end() {
|
||||
return children_begin() + children_count_;
|
||||
}
|
||||
|
||||
Isolate* HeapEntry::isolate() const { return snapshot_->profiler()->isolate(); }
|
||||
|
@ -33,11 +33,10 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
HeapGraphEdge::HeapGraphEdge(Type type, const char* name, HeapEntry* from,
|
||||
HeapEntry* to)
|
||||
: bit_field_(TypeField::encode(type) |
|
||||
FromIndexField::encode(from->index())),
|
||||
to_entry_(to),
|
||||
|
||||
HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to)
|
||||
: bit_field_(TypeField::encode(type) | FromIndexField::encode(from)),
|
||||
to_index_(to),
|
||||
name_(name) {
|
||||
DCHECK(type == kContextVariable
|
||||
|| type == kProperty
|
||||
@ -46,42 +45,56 @@ HeapGraphEdge::HeapGraphEdge(Type type, const char* name, HeapEntry* from,
|
||||
|| type == kWeak);
|
||||
}
|
||||
|
||||
HeapGraphEdge::HeapGraphEdge(Type type, int index, HeapEntry* from,
|
||||
HeapEntry* to)
|
||||
: bit_field_(TypeField::encode(type) |
|
||||
FromIndexField::encode(from->index())),
|
||||
to_entry_(to),
|
||||
|
||||
HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to)
|
||||
: bit_field_(TypeField::encode(type) | FromIndexField::encode(from)),
|
||||
to_index_(to),
|
||||
index_(index) {
|
||||
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)
|
||||
: type_(type),
|
||||
index_(index),
|
||||
children_count_(0),
|
||||
children_index_(-1),
|
||||
self_size_(self_size),
|
||||
snapshot_(snapshot),
|
||||
name_(name),
|
||||
id_(id),
|
||||
trace_node_id_(trace_node_id) {
|
||||
DCHECK_GE(index, 0);
|
||||
}
|
||||
trace_node_id_(trace_node_id) { }
|
||||
|
||||
|
||||
void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
|
||||
const char* name,
|
||||
HeapEntry* entry) {
|
||||
HeapGraphEdge edge(type, name, this->index(), entry->index());
|
||||
snapshot_->edges().push_back(edge);
|
||||
++children_count_;
|
||||
snapshot_->edges().emplace_back(type, name, this, entry);
|
||||
}
|
||||
|
||||
|
||||
void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
|
||||
int index,
|
||||
HeapEntry* entry) {
|
||||
HeapGraphEdge edge(type, index, this->index(), entry->index());
|
||||
snapshot_->edges().push_back(edge);
|
||||
++children_count_;
|
||||
snapshot_->edges().emplace_back(type, index, this, entry);
|
||||
}
|
||||
|
||||
|
||||
void HeapEntry::Print(
|
||||
const char* prefix, const char* edge_name, int max_depth, int indent) {
|
||||
STATIC_ASSERT(sizeof(unsigned) == sizeof(id()));
|
||||
@ -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
|
||||
// as small as possible. Check assumptions about data structure sizes.
|
||||
STATIC_ASSERT((kPointerSize == 4 && sizeof(HeapGraphEdge) == 12) ||
|
||||
(kPointerSize == 8 && sizeof(HeapGraphEdge) == 24));
|
||||
STATIC_ASSERT((kPointerSize == 4 && sizeof(HeapEntry) == 28) ||
|
||||
(kPointerSize == 8 && sizeof(HeapEntry) == 40));
|
||||
memset(&gc_subroot_entries_, 0, sizeof(gc_subroot_entries_));
|
||||
STATIC_ASSERT(((kPointerSize == 4) && (sizeof(HeapGraphEdge) == 12)) ||
|
||||
((kPointerSize == 8) && (sizeof(HeapGraphEdge) == 24)));
|
||||
STATIC_ASSERT(((kPointerSize == 4) && (sizeof(HeapEntry) == 28)) ||
|
||||
((kPointerSize == 8) && (sizeof(HeapEntry) == 40)));
|
||||
for (int i = 0; i < static_cast<int>(Root::kNumberOfRoots); ++i) {
|
||||
gc_subroot_indexes_[i] = HeapEntry::kNoEntry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HeapSnapshot::Delete() {
|
||||
profiler_->RemoveSnapshot(this);
|
||||
}
|
||||
|
||||
|
||||
void HeapSnapshot::RememberLastJSObjectId() {
|
||||
max_snapshot_js_object_id_ = profiler_->heap_object_map()->last_assigned_id();
|
||||
}
|
||||
|
||||
|
||||
void HeapSnapshot::AddSyntheticRootEntries() {
|
||||
AddRootEntry();
|
||||
AddGcRootsEntry();
|
||||
@ -192,30 +215,42 @@ void HeapSnapshot::AddSyntheticRootEntries() {
|
||||
DCHECK_EQ(HeapObjectsMap::kFirstAvailableObjectId, id);
|
||||
}
|
||||
|
||||
void HeapSnapshot::AddRootEntry() {
|
||||
DCHECK_NULL(root_entry_);
|
||||
|
||||
HeapEntry* HeapSnapshot::AddRootEntry() {
|
||||
DCHECK_EQ(root_index_, HeapEntry::kNoEntry);
|
||||
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());
|
||||
HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
|
||||
"",
|
||||
HeapObjectsMap::kInternalRootObjectId,
|
||||
0,
|
||||
0);
|
||||
root_index_ = entry->index();
|
||||
DCHECK_EQ(root_index_, 0);
|
||||
return entry;
|
||||
}
|
||||
|
||||
void HeapSnapshot::AddGcRootsEntry() {
|
||||
DCHECK_NULL(gc_roots_entry_);
|
||||
gc_roots_entry_ = AddEntry(HeapEntry::kSynthetic, "(GC roots)",
|
||||
HeapObjectsMap::kGcRootsObjectId, 0, 0);
|
||||
|
||||
HeapEntry* HeapSnapshot::AddGcRootsEntry() {
|
||||
DCHECK_EQ(gc_roots_index_, HeapEntry::kNoEntry);
|
||||
HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
|
||||
"(GC roots)",
|
||||
HeapObjectsMap::kGcRootsObjectId,
|
||||
0,
|
||||
0);
|
||||
gc_roots_index_ = entry->index();
|
||||
return entry;
|
||||
}
|
||||
|
||||
void HeapSnapshot::AddGcSubrootEntry(Root root, SnapshotObjectId id) {
|
||||
DCHECK_NULL(gc_subroot_entries_[static_cast<int>(root)]);
|
||||
gc_subroot_entries_[static_cast<int>(root)] =
|
||||
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);
|
||||
gc_subroot_indexes_[static_cast<int>(root)] = entry->index();
|
||||
return entry;
|
||||
}
|
||||
|
||||
void HeapSnapshot::AddLocation(HeapEntry* entry, int scriptId, int line,
|
||||
int col) {
|
||||
locations_.emplace_back(entry->index(), scriptId, line, col);
|
||||
void HeapSnapshot::AddLocation(int entry, int scriptId, int line, int col) {
|
||||
locations_.emplace_back(entry, scriptId, line, col);
|
||||
}
|
||||
|
||||
HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
|
||||
@ -223,35 +258,52 @@ HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
|
||||
SnapshotObjectId id,
|
||||
size_t size,
|
||||
unsigned trace_node_id) {
|
||||
DCHECK(!is_complete());
|
||||
entries_.emplace_back(this, static_cast<int>(entries_.size()), type, name, id,
|
||||
size, trace_node_id);
|
||||
DCHECK(sorted_entries_.empty());
|
||||
entries_.emplace_back(this, type, name, id, size, trace_node_id);
|
||||
return &entries_.back();
|
||||
}
|
||||
|
||||
|
||||
void HeapSnapshot::FillChildren() {
|
||||
DCHECK(children().empty());
|
||||
children().resize(edges().size());
|
||||
int children_index = 0;
|
||||
for (HeapEntry& entry : entries()) {
|
||||
children_index = entry.set_children_index(children_index);
|
||||
}
|
||||
DCHECK_EQ(edges().size(), static_cast<size_t>(children_index));
|
||||
children().resize(edges().size());
|
||||
for (HeapGraphEdge& edge : edges()) {
|
||||
edge.ReplaceToIndexWithEntry(this);
|
||||
edge.from()->add_child(&edge);
|
||||
}
|
||||
}
|
||||
|
||||
HeapEntry* HeapSnapshot::GetEntryById(SnapshotObjectId id) {
|
||||
if (entries_by_id_cache_.empty()) {
|
||||
CHECK(is_complete());
|
||||
entries_by_id_cache_.reserve(entries_.size());
|
||||
for (HeapEntry& entry : entries_) {
|
||||
entries_by_id_cache_.emplace(entry.id(), &entry);
|
||||
}
|
||||
std::vector<HeapEntry*>* entries_by_id = GetSortedEntriesList();
|
||||
|
||||
auto it = std::lower_bound(
|
||||
entries_by_id->begin(), entries_by_id->end(), id,
|
||||
[](HeapEntry* first, SnapshotObjectId val) { return first->id() < val; });
|
||||
|
||||
if (it == entries_by_id->end() || (*it)->id() != id) return nullptr;
|
||||
return *it;
|
||||
}
|
||||
|
||||
struct SortByIds {
|
||||
bool operator()(const HeapEntry* entry1_ptr, const HeapEntry* entry2_ptr) {
|
||||
return entry1_ptr->id() < entry2_ptr->id();
|
||||
}
|
||||
auto it = entries_by_id_cache_.find(id);
|
||||
return it != entries_by_id_cache_.end() ? it->second : nullptr;
|
||||
};
|
||||
|
||||
std::vector<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() {
|
||||
if (sorted_entries_.empty()) {
|
||||
sorted_entries_.reserve(entries_.size());
|
||||
for (HeapEntry& entry : entries_) {
|
||||
sorted_entries_.push_back(&entry);
|
||||
}
|
||||
std::sort(sorted_entries_.begin(), sorted_entries_.end(), SortByIds());
|
||||
}
|
||||
return &sorted_entries_;
|
||||
}
|
||||
|
||||
void HeapSnapshot::Print(int max_depth) {
|
||||
@ -503,7 +555,7 @@ HeapEntry* V8HeapExplorer::AllocateEntry(HeapThing ptr) {
|
||||
return AddEntry(reinterpret_cast<HeapObject*>(ptr));
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractLocation(HeapEntry* entry, HeapObject* object) {
|
||||
void V8HeapExplorer::ExtractLocation(int entry, HeapObject* object) {
|
||||
if (object->IsJSFunction()) {
|
||||
JSFunction* func = JSFunction::cast(object);
|
||||
ExtractLocationForJSFunction(entry, func);
|
||||
@ -521,8 +573,7 @@ void V8HeapExplorer::ExtractLocation(HeapEntry* entry, HeapObject* object) {
|
||||
}
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractLocationForJSFunction(HeapEntry* entry,
|
||||
JSFunction* func) {
|
||||
void V8HeapExplorer::ExtractLocationForJSFunction(int entry, JSFunction* func) {
|
||||
if (!func->shared()->script()->IsScript()) return;
|
||||
Script* script = Script::cast(func->shared()->script());
|
||||
int scriptId = script->id();
|
||||
@ -625,20 +676,25 @@ HeapEntry* V8HeapExplorer::AddEntry(Address address,
|
||||
return snapshot_->AddEntry(type, name, object_id, size, trace_node_id);
|
||||
}
|
||||
|
||||
|
||||
class SnapshotFiller {
|
||||
public:
|
||||
SnapshotFiller(HeapSnapshot* snapshot,
|
||||
HeapSnapshotGenerator::HeapEntriesMap* entries_map)
|
||||
: names_(snapshot->profiler()->names()), entries_map_(entries_map) {}
|
||||
: snapshot_(snapshot),
|
||||
names_(snapshot->profiler()->names()),
|
||||
entries_map_(entries_map) {}
|
||||
|
||||
HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
|
||||
return entries_map_->emplace(ptr, allocator->AllocateEntry(ptr))
|
||||
.first->second;
|
||||
HeapEntry* entry = allocator->AllocateEntry(ptr);
|
||||
entries_map_->emplace(ptr, entry->index());
|
||||
return entry;
|
||||
}
|
||||
|
||||
HeapEntry* FindEntry(HeapThing 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) {
|
||||
@ -646,32 +702,43 @@ class SnapshotFiller {
|
||||
return entry != nullptr ? entry : AddEntry(ptr, allocator);
|
||||
}
|
||||
|
||||
void SetIndexedReference(HeapGraphEdge::Type type, HeapEntry* parent,
|
||||
int index, HeapEntry* child) {
|
||||
parent->SetIndexedReference(type, index, child);
|
||||
void SetIndexedReference(HeapGraphEdge::Type type,
|
||||
int parent,
|
||||
int index,
|
||||
HeapEntry* child_entry) {
|
||||
HeapEntry* parent_entry = &snapshot_->entries()[parent];
|
||||
parent_entry->SetIndexedReference(type, index, child_entry);
|
||||
}
|
||||
|
||||
void SetIndexedAutoIndexReference(HeapGraphEdge::Type type, HeapEntry* parent,
|
||||
HeapEntry* child) {
|
||||
int index = parent->children_count() + 1;
|
||||
parent->SetIndexedReference(type, index, child);
|
||||
void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
|
||||
int parent,
|
||||
HeapEntry* child_entry) {
|
||||
HeapEntry* parent_entry = &snapshot_->entries()[parent];
|
||||
int index = parent_entry->children_count() + 1;
|
||||
parent_entry->SetIndexedReference(type, index, child_entry);
|
||||
}
|
||||
|
||||
void SetNamedReference(HeapGraphEdge::Type type, HeapEntry* parent,
|
||||
const char* reference_name, HeapEntry* child) {
|
||||
parent->SetNamedReference(type, reference_name, child);
|
||||
void SetNamedReference(HeapGraphEdge::Type type,
|
||||
int parent,
|
||||
const char* reference_name,
|
||||
HeapEntry* child_entry) {
|
||||
HeapEntry* parent_entry = &snapshot_->entries()[parent];
|
||||
parent_entry->SetNamedReference(type, reference_name, child_entry);
|
||||
}
|
||||
|
||||
void SetNamedAutoIndexReference(HeapGraphEdge::Type type, HeapEntry* parent,
|
||||
const char* description, HeapEntry* child) {
|
||||
int index = parent->children_count() + 1;
|
||||
void SetNamedAutoIndexReference(HeapGraphEdge::Type type, int parent,
|
||||
const char* description,
|
||||
HeapEntry* child_entry) {
|
||||
HeapEntry* parent_entry = &snapshot_->entries()[parent];
|
||||
int index = parent_entry->children_count() + 1;
|
||||
const char* name = description
|
||||
? names_->GetFormatted("%d / %s", index, description)
|
||||
: names_->GetName(index);
|
||||
parent->SetNamedReference(type, name, child);
|
||||
parent_entry->SetNamedReference(type, name, child_entry);
|
||||
}
|
||||
|
||||
private:
|
||||
HeapSnapshot* snapshot_;
|
||||
StringsStorage* names_;
|
||||
HeapSnapshotGenerator::HeapEntriesMap* entries_map_;
|
||||
};
|
||||
@ -711,7 +778,7 @@ int V8HeapExplorer::EstimateObjectsCount() {
|
||||
class IndexedReferencesExtractor : public ObjectVisitor {
|
||||
public:
|
||||
IndexedReferencesExtractor(V8HeapExplorer* generator, HeapObject* parent_obj,
|
||||
HeapEntry* parent)
|
||||
int parent)
|
||||
: generator_(generator),
|
||||
parent_obj_(parent_obj),
|
||||
parent_start_(HeapObject::RawField(parent_obj_, 0)),
|
||||
@ -750,10 +817,10 @@ class IndexedReferencesExtractor : public ObjectVisitor {
|
||||
HeapObject* parent_obj_;
|
||||
Object** parent_start_;
|
||||
Object** parent_end_;
|
||||
HeapEntry* parent_;
|
||||
int parent_;
|
||||
};
|
||||
|
||||
void V8HeapExplorer::ExtractReferences(HeapEntry* entry, HeapObject* obj) {
|
||||
void V8HeapExplorer::ExtractReferences(int entry, HeapObject* obj) {
|
||||
if (obj->IsJSGlobalProxy()) {
|
||||
ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
|
||||
} else if (obj->IsJSArrayBuffer()) {
|
||||
@ -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,
|
||||
"native_context", proxy->native_context(),
|
||||
JSGlobalProxy::kNativeContextOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry,
|
||||
JSObject* js_obj) {
|
||||
|
||||
void V8HeapExplorer::ExtractJSObjectReferences(
|
||||
int entry, JSObject* js_obj) {
|
||||
HeapObject* obj = js_obj;
|
||||
ExtractPropertyReferences(js_obj, entry);
|
||||
ExtractElementReferences(js_obj, entry);
|
||||
@ -908,7 +977,8 @@ void V8HeapExplorer::ExtractJSObjectReferences(HeapEntry* entry,
|
||||
JSObject::kElementsOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, String* string) {
|
||||
|
||||
void V8HeapExplorer::ExtractStringReferences(int entry, String* string) {
|
||||
if (string->IsConsString()) {
|
||||
ConsString* cs = ConsString::cast(string);
|
||||
SetInternalReference(cs, entry, "first", cs->first(),
|
||||
@ -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,
|
||||
"name", symbol->name(),
|
||||
Symbol::kNameOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractJSCollectionReferences(HeapEntry* entry,
|
||||
|
||||
void V8HeapExplorer::ExtractJSCollectionReferences(int entry,
|
||||
JSCollection* collection) {
|
||||
SetInternalReference(collection, entry, "table", collection->table(),
|
||||
JSCollection::kTableOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractJSWeakCollectionReferences(HeapEntry* entry,
|
||||
void V8HeapExplorer::ExtractJSWeakCollectionReferences(int entry,
|
||||
JSWeakCollection* obj) {
|
||||
SetInternalReference(obj, entry, "table", obj->table(),
|
||||
JSWeakCollection::kTableOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractEphemeronHashTableReferences(
|
||||
HeapEntry* entry, EphemeronHashTable* table) {
|
||||
int entry, EphemeronHashTable* table) {
|
||||
for (int i = 0, capacity = table->Capacity(); i < capacity; ++i) {
|
||||
int key_index = EphemeronHashTable::EntryToIndex(i) +
|
||||
EphemeronHashTable::kEntryKeyIndex;
|
||||
@ -957,18 +1029,18 @@ void V8HeapExplorer::ExtractEphemeronHashTableReferences(
|
||||
SetWeakReference(table, entry, value_index, value,
|
||||
table->OffsetOfElementAt(value_index));
|
||||
HeapEntry* key_entry = GetEntry(key);
|
||||
int key_entry_index = key_entry->index();
|
||||
HeapEntry* value_entry = GetEntry(value);
|
||||
if (key_entry && value_entry) {
|
||||
const char* edge_name =
|
||||
names_->GetFormatted("key %s in WeakMap", key_entry->name());
|
||||
filler_->SetNamedAutoIndexReference(HeapGraphEdge::kInternal, key_entry,
|
||||
edge_name, value_entry);
|
||||
filler_->SetNamedAutoIndexReference(
|
||||
HeapGraphEdge::kInternal, key_entry_index, edge_name, value_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractContextReferences(HeapEntry* entry,
|
||||
Context* context) {
|
||||
void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
|
||||
if (!context->IsNativeContext() && context->is_declaration_context()) {
|
||||
ScopeInfo* scope_info = context->scope_info();
|
||||
// Add context allocated locals.
|
||||
@ -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();
|
||||
HeapObject* raw_transitions_or_prototype_info;
|
||||
if (maybe_raw_transitions_or_prototype_info->GetHeapObjectIfWeak(
|
||||
@ -1081,8 +1154,9 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Map* map) {
|
||||
Map::kDependentCodeOffset);
|
||||
}
|
||||
|
||||
|
||||
void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
|
||||
HeapEntry* entry, SharedFunctionInfo* shared) {
|
||||
int entry, SharedFunctionInfo* shared) {
|
||||
HeapObject* obj = shared;
|
||||
String* shared_name = shared->DebugName();
|
||||
const char* name = nullptr;
|
||||
@ -1113,7 +1187,7 @@ void V8HeapExplorer::ExtractSharedFunctionInfoReferences(
|
||||
SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) {
|
||||
void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) {
|
||||
HeapObject* obj = script;
|
||||
SetInternalReference(obj, entry,
|
||||
"source", script->source(),
|
||||
@ -1130,8 +1204,9 @@ void V8HeapExplorer::ExtractScriptReferences(HeapEntry* entry, Script* script) {
|
||||
Script::kLineEndsOffset);
|
||||
}
|
||||
|
||||
|
||||
void V8HeapExplorer::ExtractAccessorInfoReferences(
|
||||
HeapEntry* entry, AccessorInfo* accessor_info) {
|
||||
int entry, AccessorInfo* accessor_info) {
|
||||
SetInternalReference(accessor_info, entry, "name", accessor_info->name(),
|
||||
AccessorInfo::kNameOffset);
|
||||
SetInternalReference(accessor_info, entry, "expected_receiver_type",
|
||||
@ -1145,8 +1220,8 @@ void V8HeapExplorer::ExtractAccessorInfoReferences(
|
||||
AccessorInfo::kDataOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractAccessorPairReferences(HeapEntry* entry,
|
||||
AccessorPair* accessors) {
|
||||
void V8HeapExplorer::ExtractAccessorPairReferences(
|
||||
int entry, AccessorPair* accessors) {
|
||||
SetInternalReference(accessors, entry, "getter", accessors->getter(),
|
||||
AccessorPair::kGetterOffset);
|
||||
SetInternalReference(accessors, entry, "setter", accessors->setter(),
|
||||
@ -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);
|
||||
TagObject(code->relocation_info(), "(code relocation info)");
|
||||
SetInternalReference(code, entry,
|
||||
@ -1181,18 +1256,18 @@ void V8HeapExplorer::ExtractCodeReferences(HeapEntry* entry, Code* code) {
|
||||
Code::kSourcePositionTableOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractCellReferences(HeapEntry* entry, Cell* cell) {
|
||||
void V8HeapExplorer::ExtractCellReferences(int entry, Cell* cell) {
|
||||
SetInternalReference(cell, entry, "value", cell->value(), Cell::kValueOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractFeedbackCellReferences(
|
||||
HeapEntry* entry, FeedbackCell* feedback_cell) {
|
||||
int entry, FeedbackCell* feedback_cell) {
|
||||
TagObject(feedback_cell, "(feedback cell)");
|
||||
SetInternalReference(feedback_cell, entry, "value", feedback_cell->value(),
|
||||
FeedbackCell::kValueOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractPropertyCellReferences(HeapEntry* entry,
|
||||
void V8HeapExplorer::ExtractPropertyCellReferences(int entry,
|
||||
PropertyCell* cell) {
|
||||
SetInternalReference(cell, entry, "value", cell->value(),
|
||||
PropertyCell::kValueOffset);
|
||||
@ -1201,7 +1276,7 @@ void V8HeapExplorer::ExtractPropertyCellReferences(HeapEntry* entry,
|
||||
PropertyCell::kDependentCodeOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractAllocationSiteReferences(HeapEntry* entry,
|
||||
void V8HeapExplorer::ExtractAllocationSiteReferences(int entry,
|
||||
AllocationSite* site) {
|
||||
SetInternalReference(site, entry, "transition_info",
|
||||
site->transition_info_or_boilerplate(),
|
||||
@ -1214,7 +1289,7 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(HeapEntry* entry,
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractArrayBoilerplateDescriptionReferences(
|
||||
HeapEntry* entry, ArrayBoilerplateDescription* value) {
|
||||
int entry, ArrayBoilerplateDescription* value) {
|
||||
SetInternalReference(value, entry, "constant_elements",
|
||||
value->constant_elements(),
|
||||
ArrayBoilerplateDescription::kConstantElementsOffset);
|
||||
@ -1236,8 +1311,8 @@ class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator {
|
||||
V8HeapExplorer* explorer_;
|
||||
};
|
||||
|
||||
void V8HeapExplorer::ExtractJSArrayBufferReferences(HeapEntry* entry,
|
||||
JSArrayBuffer* buffer) {
|
||||
void V8HeapExplorer::ExtractJSArrayBufferReferences(
|
||||
int entry, JSArrayBuffer* buffer) {
|
||||
// Setup a reference to a native memory backing_store object.
|
||||
if (!buffer->backing_store())
|
||||
return;
|
||||
@ -1249,15 +1324,14 @@ void V8HeapExplorer::ExtractJSArrayBufferReferences(HeapEntry* entry,
|
||||
entry, "backing_store", data_entry);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractJSPromiseReferences(HeapEntry* entry,
|
||||
JSPromise* promise) {
|
||||
void V8HeapExplorer::ExtractJSPromiseReferences(int entry, JSPromise* promise) {
|
||||
SetInternalReference(promise, entry, "reactions_or_result",
|
||||
promise->reactions_or_result(),
|
||||
JSPromise::kReactionsOrResultOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractJSGeneratorObjectReferences(
|
||||
HeapEntry* entry, JSGeneratorObject* generator) {
|
||||
int entry, JSGeneratorObject* generator) {
|
||||
SetInternalReference(generator, entry, "function", generator->function(),
|
||||
JSGeneratorObject::kFunctionOffset);
|
||||
SetInternalReference(generator, entry, "context", generator->context(),
|
||||
@ -1269,8 +1343,7 @@ void V8HeapExplorer::ExtractJSGeneratorObjectReferences(
|
||||
JSGeneratorObject::kParametersAndRegistersOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractFixedArrayReferences(HeapEntry* entry,
|
||||
FixedArray* array) {
|
||||
void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) {
|
||||
for (int i = 0, l = array->length(); i < l; ++i) {
|
||||
DCHECK(!HasWeakHeapObjectTag(array->get(i)));
|
||||
SetInternalReference(array, entry, i, array->get(i),
|
||||
@ -1279,7 +1352,7 @@ void V8HeapExplorer::ExtractFixedArrayReferences(HeapEntry* entry,
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractFeedbackVectorReferences(
|
||||
HeapEntry* entry, FeedbackVector* feedback_vector) {
|
||||
int entry, FeedbackVector* feedback_vector) {
|
||||
MaybeObject* code = feedback_vector->optimized_code_weak_or_smi();
|
||||
HeapObject* code_heap_object;
|
||||
if (code->GetHeapObjectIfWeak(&code_heap_object)) {
|
||||
@ -1289,8 +1362,8 @@ void V8HeapExplorer::ExtractFeedbackVectorReferences(
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void V8HeapExplorer::ExtractWeakArrayReferences(int header_size,
|
||||
HeapEntry* entry, T* array) {
|
||||
void V8HeapExplorer::ExtractWeakArrayReferences(int header_size, int entry,
|
||||
T* array) {
|
||||
for (int i = 0; i < array->length(); ++i) {
|
||||
MaybeObject* object = array->Get(i);
|
||||
HeapObject* heap_object;
|
||||
@ -1304,8 +1377,7 @@ void V8HeapExplorer::ExtractWeakArrayReferences(int header_size,
|
||||
}
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
|
||||
HeapEntry* entry) {
|
||||
void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
|
||||
Isolate* isolate = js_obj->GetIsolate();
|
||||
if (js_obj->HasFastProperties()) {
|
||||
DescriptorArray* descs = js_obj->map()->instance_descriptors();
|
||||
@ -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,
|
||||
int field_offset) {
|
||||
if (!callback_obj->IsAccessorPair()) return;
|
||||
@ -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();
|
||||
if (js_obj->HasObjectElements()) {
|
||||
FixedArray* elements = FixedArray::cast(js_obj->elements());
|
||||
@ -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();
|
||||
for (int i = 0; i < length; ++i) {
|
||||
Object* o = js_obj->GetEmbedderField(i);
|
||||
@ -1506,7 +1579,8 @@ bool V8HeapExplorer::IterateAndExtractReferences(SnapshotFiller* filler) {
|
||||
visited_fields_.resize(max_pointer, false);
|
||||
}
|
||||
|
||||
HeapEntry* entry = GetEntry(obj);
|
||||
HeapEntry* heap_entry = GetEntry(obj);
|
||||
int entry = heap_entry->index();
|
||||
ExtractReferences(entry, obj);
|
||||
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
|
||||
// Extract unvisited fields as hidden references and restore tags
|
||||
@ -1560,10 +1634,11 @@ bool V8HeapExplorer::IsEssentialHiddenReference(Object* parent,
|
||||
}
|
||||
|
||||
void V8HeapExplorer::SetContextReference(HeapObject* parent_obj,
|
||||
HeapEntry* parent_entry,
|
||||
int parent_entry,
|
||||
String* reference_name,
|
||||
Object* child_obj, int field_offset) {
|
||||
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);
|
||||
if (child_entry == nullptr) return;
|
||||
filler_->SetNamedReference(HeapGraphEdge::kContextVariable, parent_entry,
|
||||
@ -1578,32 +1653,37 @@ void V8HeapExplorer::MarkVisitedField(int offset) {
|
||||
visited_fields_[index] = true;
|
||||
}
|
||||
|
||||
|
||||
void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj,
|
||||
HeapEntry* parent_entry,
|
||||
int parent_entry,
|
||||
const char* reference_name,
|
||||
Object* child_obj) {
|
||||
DCHECK_EQ(parent_entry, GetEntry(parent_obj));
|
||||
DCHECK(parent_entry == GetEntry(parent_obj)->index());
|
||||
HeapEntry* child_entry = GetEntry(child_obj);
|
||||
if (child_entry == nullptr) return;
|
||||
filler_->SetNamedReference(HeapGraphEdge::kShortcut, parent_entry,
|
||||
reference_name, child_entry);
|
||||
}
|
||||
|
||||
|
||||
void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
|
||||
HeapEntry* parent_entry, int index,
|
||||
int parent_entry,
|
||||
int index,
|
||||
Object* child_obj) {
|
||||
DCHECK_EQ(parent_entry, GetEntry(parent_obj));
|
||||
DCHECK(parent_entry == GetEntry(parent_obj)->index());
|
||||
HeapEntry* child_entry = GetEntry(child_obj);
|
||||
if (child_entry == nullptr) return;
|
||||
filler_->SetIndexedReference(HeapGraphEdge::kElement, parent_entry, index,
|
||||
child_entry);
|
||||
}
|
||||
|
||||
|
||||
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
|
||||
HeapEntry* parent_entry,
|
||||
int parent_entry,
|
||||
const char* reference_name,
|
||||
Object* child_obj, int field_offset) {
|
||||
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);
|
||||
if (child_entry == nullptr) return;
|
||||
if (IsEssentialObject(child_obj)) {
|
||||
@ -1615,10 +1695,13 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
|
||||
MarkVisitedField(field_offset);
|
||||
}
|
||||
|
||||
|
||||
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
|
||||
HeapEntry* parent_entry, int index,
|
||||
Object* child_obj, int field_offset) {
|
||||
DCHECK_EQ(parent_entry, GetEntry(parent_obj));
|
||||
int parent_entry,
|
||||
int index,
|
||||
Object* child_obj,
|
||||
int field_offset) {
|
||||
DCHECK(parent_entry == GetEntry(parent_obj)->index());
|
||||
HeapEntry* child_entry = GetEntry(child_obj);
|
||||
if (child_entry == nullptr) return;
|
||||
if (IsEssentialObject(child_obj)) {
|
||||
@ -1631,9 +1714,9 @@ void V8HeapExplorer::SetInternalReference(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) {
|
||||
DCHECK_EQ(parent_entry, GetEntry(parent_obj));
|
||||
DCHECK(parent_entry == GetEntry(parent_obj)->index());
|
||||
HeapEntry* child_entry = GetEntry(child_obj);
|
||||
if (child_entry != nullptr && IsEssentialObject(child_obj) &&
|
||||
IsEssentialHiddenReference(parent_obj, field_offset)) {
|
||||
@ -1642,11 +1725,13 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
|
||||
HeapEntry* parent_entry,
|
||||
int parent_entry,
|
||||
const char* reference_name,
|
||||
Object* child_obj, int field_offset) {
|
||||
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);
|
||||
if (child_entry == nullptr) return;
|
||||
if (IsEssentialObject(child_obj)) {
|
||||
@ -1658,10 +1743,13 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
|
||||
MarkVisitedField(field_offset);
|
||||
}
|
||||
|
||||
|
||||
void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
|
||||
HeapEntry* parent_entry, int index,
|
||||
Object* child_obj, int field_offset) {
|
||||
DCHECK_EQ(parent_entry, GetEntry(parent_obj));
|
||||
int parent_entry,
|
||||
int index,
|
||||
Object* child_obj,
|
||||
int field_offset) {
|
||||
DCHECK(parent_entry == GetEntry(parent_obj)->index());
|
||||
HeapEntry* child_entry = GetEntry(child_obj);
|
||||
if (child_entry == nullptr) return;
|
||||
if (IsEssentialObject(child_obj)) {
|
||||
@ -1674,10 +1762,9 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
|
||||
}
|
||||
|
||||
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,
|
||||
int field_offset) {
|
||||
DCHECK_EQ(parent_entry, GetEntry(parent_obj));
|
||||
if (kind == kAccessor) {
|
||||
ExtractAccessorPairProperty(parent_obj, parent_entry, reference_name,
|
||||
child_obj, field_offset);
|
||||
@ -1687,10 +1774,14 @@ void V8HeapExplorer::SetDataOrAccessorPropertyReference(
|
||||
}
|
||||
}
|
||||
|
||||
void V8HeapExplorer::SetPropertyReference(
|
||||
HeapObject* parent_obj, HeapEntry* parent_entry, Name* reference_name,
|
||||
Object* child_obj, const char* name_format_string, int field_offset) {
|
||||
DCHECK_EQ(parent_entry, GetEntry(parent_obj));
|
||||
|
||||
void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
|
||||
int parent_entry,
|
||||
Name* reference_name,
|
||||
Object* child_obj,
|
||||
const char* name_format_string,
|
||||
int field_offset) {
|
||||
DCHECK(parent_entry == GetEntry(parent_obj)->index());
|
||||
HeapEntry* child_entry = GetEntry(child_obj);
|
||||
if (child_entry == nullptr) return;
|
||||
HeapGraphEdge::Type type =
|
||||
@ -1712,19 +1803,22 @@ void V8HeapExplorer::SetPropertyReference(
|
||||
|
||||
void V8HeapExplorer::SetRootGcRootsReference() {
|
||||
filler_->SetIndexedAutoIndexReference(
|
||||
HeapGraphEdge::kElement, snapshot_->root(), snapshot_->gc_roots());
|
||||
HeapGraphEdge::kElement,
|
||||
snapshot_->root()->index(),
|
||||
snapshot_->gc_roots());
|
||||
}
|
||||
|
||||
void V8HeapExplorer::SetUserGlobalReference(Object* child_obj) {
|
||||
HeapEntry* child_entry = GetEntry(child_obj);
|
||||
DCHECK_NOT_NULL(child_entry);
|
||||
filler_->SetNamedAutoIndexReference(HeapGraphEdge::kShortcut,
|
||||
snapshot_->root(), nullptr, child_entry);
|
||||
snapshot_->root()->index(), nullptr,
|
||||
child_entry);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::SetGcRootsReference(Root root) {
|
||||
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
|
||||
snapshot_->gc_roots(),
|
||||
snapshot_->gc_roots()->index(),
|
||||
snapshot_->gc_subroot(root));
|
||||
}
|
||||
|
||||
@ -1736,10 +1830,11 @@ void V8HeapExplorer::SetGcSubrootReference(Root root, const char* description,
|
||||
HeapGraphEdge::Type edge_type =
|
||||
is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kInternal;
|
||||
if (name != nullptr) {
|
||||
filler_->SetNamedReference(edge_type, snapshot_->gc_subroot(root), name,
|
||||
child_entry);
|
||||
filler_->SetNamedReference(edge_type, snapshot_->gc_subroot(root)->index(),
|
||||
name, child_entry);
|
||||
} else {
|
||||
filler_->SetNamedAutoIndexReference(edge_type, snapshot_->gc_subroot(root),
|
||||
filler_->SetNamedAutoIndexReference(edge_type,
|
||||
snapshot_->gc_subroot(root)->index(),
|
||||
description, child_entry);
|
||||
}
|
||||
|
||||
@ -2076,9 +2171,10 @@ void NativeObjectsExplorer::FillEdges() {
|
||||
Handle<Object> parent_object = v8::Utils::OpenHandle(
|
||||
*pair.first->Get(reinterpret_cast<v8::Isolate*>(isolate_)));
|
||||
HeapObject* parent = HeapObject::cast(*parent_object);
|
||||
HeapEntry* parent_entry =
|
||||
filler_->FindOrAddEntry(parent, native_entries_allocator_.get());
|
||||
DCHECK_NOT_NULL(parent_entry);
|
||||
int parent_entry =
|
||||
filler_->FindOrAddEntry(parent, native_entries_allocator_.get())
|
||||
->index();
|
||||
DCHECK_NE(parent_entry, HeapEntry::kNoEntry);
|
||||
Handle<Object> child_object = v8::Utils::OpenHandle(
|
||||
*pair.second->Get(reinterpret_cast<v8::Isolate*>(isolate_)));
|
||||
HeapObject* child = HeapObject::cast(*child_object);
|
||||
@ -2131,7 +2227,7 @@ bool NativeObjectsExplorer::IterateAndExtractReferences(
|
||||
for (const auto& node : graph.nodes()) {
|
||||
if (node->IsRootNode()) {
|
||||
filler_->SetIndexedAutoIndexReference(
|
||||
HeapGraphEdge::kElement, snapshot_->root(),
|
||||
HeapGraphEdge::kElement, snapshot_->root()->index(),
|
||||
EntryForEmbedderGraphNode(node.get()));
|
||||
}
|
||||
// Adjust the name and the type of the V8 wrapper node.
|
||||
@ -2150,14 +2246,17 @@ bool NativeObjectsExplorer::IterateAndExtractReferences(
|
||||
// The |from| and |to| can nullptr if the corrsponding node is a V8 node
|
||||
// pointing to a Smi.
|
||||
if (!from) continue;
|
||||
// Adding an entry for |edge.to| can invalidate the |from| entry because
|
||||
// it is an address in std::vector. Use index instead of pointer.
|
||||
int from_index = from->index();
|
||||
HeapEntry* to = EntryForEmbedderGraphNode(edge.to);
|
||||
if (to) {
|
||||
if (edge.name == nullptr) {
|
||||
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, from,
|
||||
to);
|
||||
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
|
||||
from_index, to);
|
||||
} else {
|
||||
filler_->SetNamedReference(HeapGraphEdge::kInternal, from, edge.name,
|
||||
to);
|
||||
filler_->SetNamedReference(HeapGraphEdge::kInternal, from_index,
|
||||
edge.name, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2198,8 +2297,11 @@ void NativeObjectsExplorer::SetNativeRootReference(
|
||||
FindOrAddGroupInfo(info->GetGroupLabel());
|
||||
HeapEntry* group_entry =
|
||||
filler_->FindOrAddEntry(group_info, synthetic_entries_allocator_.get());
|
||||
filler_->SetNamedAutoIndexReference(HeapGraphEdge::kInternal, group_entry,
|
||||
nullptr, child_entry);
|
||||
// |FindOrAddEntry| can move and resize the entries backing store. Reload
|
||||
// potentially-stale pointer.
|
||||
child_entry = filler_->FindEntry(info);
|
||||
filler_->SetNamedAutoIndexReference(
|
||||
HeapGraphEdge::kInternal, group_entry->index(), nullptr, child_entry);
|
||||
}
|
||||
|
||||
|
||||
@ -2210,9 +2312,12 @@ void NativeObjectsExplorer::SetWrapperNativeReferences(
|
||||
HeapEntry* info_entry =
|
||||
filler_->FindOrAddEntry(info, native_entries_allocator_.get());
|
||||
DCHECK_NOT_NULL(info_entry);
|
||||
filler_->SetNamedReference(HeapGraphEdge::kInternal, wrapper_entry, "native",
|
||||
filler_->SetNamedReference(HeapGraphEdge::kInternal,
|
||||
wrapper_entry->index(),
|
||||
"native",
|
||||
info_entry);
|
||||
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, info_entry,
|
||||
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
|
||||
info_entry->index(),
|
||||
wrapper_entry);
|
||||
}
|
||||
|
||||
@ -2223,8 +2328,10 @@ void NativeObjectsExplorer::SetRootNativeRootsReference() {
|
||||
HeapEntry* group_entry =
|
||||
filler_->FindOrAddEntry(group_info, native_entries_allocator_.get());
|
||||
DCHECK_NOT_NULL(group_entry);
|
||||
filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement,
|
||||
snapshot_->root(), group_entry);
|
||||
filler_->SetIndexedAutoIndexReference(
|
||||
HeapGraphEdge::kElement,
|
||||
snapshot_->root()->index(),
|
||||
group_entry);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2571,8 +2678,9 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
|
||||
writer_->AddString(buffer.start());
|
||||
}
|
||||
|
||||
|
||||
void HeapSnapshotJSONSerializer::SerializeEdges() {
|
||||
std::vector<HeapGraphEdge*>& edges = snapshot_->children();
|
||||
std::deque<HeapGraphEdge*>& edges = snapshot_->children();
|
||||
for (size_t i = 0; i < edges.size(); ++i) {
|
||||
DCHECK(i == 0 ||
|
||||
edges[i - 1]->from()->index() <= edges[i]->from()->index());
|
||||
@ -2608,14 +2716,16 @@ void HeapSnapshotJSONSerializer::SerializeNode(const HeapEntry* entry) {
|
||||
writer_->AddString(buffer.start());
|
||||
}
|
||||
|
||||
|
||||
void HeapSnapshotJSONSerializer::SerializeNodes() {
|
||||
const std::deque<HeapEntry>& entries = snapshot_->entries();
|
||||
std::vector<HeapEntry>& entries = snapshot_->entries();
|
||||
for (const HeapEntry& entry : entries) {
|
||||
SerializeNode(&entry);
|
||||
if (writer_->aborted()) return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HeapSnapshotJSONSerializer::SerializeSnapshot() {
|
||||
writer_->AddString("\"meta\":");
|
||||
// The object describing node serialization layout.
|
||||
|
@ -60,8 +60,9 @@ class HeapGraphEdge {
|
||||
kWeak = v8::HeapGraphEdge::kWeak
|
||||
};
|
||||
|
||||
HeapGraphEdge(Type type, const char* name, HeapEntry* from, HeapEntry* to);
|
||||
HeapGraphEdge(Type type, int index, HeapEntry* from, HeapEntry* to);
|
||||
HeapGraphEdge(Type type, const char* name, int from, int to);
|
||||
HeapGraphEdge(Type type, int index, int from, int to);
|
||||
void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);
|
||||
|
||||
Type type() const { return TypeField::decode(bit_field_); }
|
||||
int index() const {
|
||||
@ -85,7 +86,12 @@ class HeapGraphEdge {
|
||||
class TypeField : public BitField<Type, 0, 3> {};
|
||||
class FromIndexField : public BitField<int, 3, 29> {};
|
||||
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 {
|
||||
int index_;
|
||||
const char* name_;
|
||||
@ -113,9 +119,15 @@ class HeapEntry {
|
||||
kSymbol = v8::HeapGraphNode::kSymbol,
|
||||
kBigInt = v8::HeapGraphNode::kBigInt
|
||||
};
|
||||
static const int kNoEntry;
|
||||
|
||||
HeapEntry(HeapSnapshot* snapshot, int index, Type type, const char* name,
|
||||
SnapshotObjectId id, size_t self_size, unsigned trace_node_id);
|
||||
HeapEntry() = default;
|
||||
HeapEntry(HeapSnapshot* snapshot,
|
||||
Type type,
|
||||
const char* name,
|
||||
SnapshotObjectId id,
|
||||
size_t self_size,
|
||||
unsigned trace_node_id);
|
||||
|
||||
HeapSnapshot* snapshot() { return snapshot_; }
|
||||
Type type() const { return static_cast<Type>(type_); }
|
||||
@ -125,8 +137,8 @@ class HeapEntry {
|
||||
SnapshotObjectId id() const { return id_; }
|
||||
size_t self_size() const { return self_size_; }
|
||||
unsigned trace_node_id() const { return trace_node_id_; }
|
||||
int index() const { return index_; }
|
||||
V8_INLINE int children_count() const;
|
||||
V8_INLINE int index() const;
|
||||
int children_count() const { return children_count_; }
|
||||
V8_INLINE int set_children_index(int index);
|
||||
V8_INLINE void add_child(HeapGraphEdge* edge);
|
||||
V8_INLINE HeapGraphEdge* child(int i);
|
||||
@ -141,18 +153,13 @@ class HeapEntry {
|
||||
const char* prefix, const char* edge_name, int max_depth, int indent);
|
||||
|
||||
private:
|
||||
V8_INLINE std::vector<HeapGraphEdge*>::iterator children_begin() const;
|
||||
V8_INLINE std::vector<HeapGraphEdge*>::iterator children_end() const;
|
||||
V8_INLINE std::deque<HeapGraphEdge*>::iterator children_begin();
|
||||
V8_INLINE std::deque<HeapGraphEdge*>::iterator children_end();
|
||||
const char* TypeAsString();
|
||||
|
||||
unsigned type_: 4;
|
||||
unsigned index_ : 28; // Supports up to ~250M objects.
|
||||
union {
|
||||
// The count is used during the snapshot build phase,
|
||||
// then it gets converted into the index by the |FillChildren| function.
|
||||
unsigned children_count_ = 0;
|
||||
unsigned children_end_index_;
|
||||
};
|
||||
int children_count_: 28;
|
||||
int children_index_;
|
||||
size_t self_size_;
|
||||
HeapSnapshot* snapshot_;
|
||||
const char* name_;
|
||||
@ -161,6 +168,7 @@ class HeapEntry {
|
||||
unsigned trace_node_id_;
|
||||
};
|
||||
|
||||
|
||||
// HeapSnapshot represents a single heap snapshot. It is stored in
|
||||
// HeapProfiler, which is also a factory for
|
||||
// HeapSnapshots. All HeapSnapshots share strings copied from JS heap
|
||||
@ -171,23 +179,22 @@ class HeapSnapshot {
|
||||
explicit HeapSnapshot(HeapProfiler* profiler);
|
||||
void Delete();
|
||||
|
||||
HeapProfiler* profiler() const { return profiler_; }
|
||||
HeapEntry* root() const { return root_entry_; }
|
||||
HeapEntry* gc_roots() const { return gc_roots_entry_; }
|
||||
HeapEntry* gc_subroot(Root root) const {
|
||||
return gc_subroot_entries_[static_cast<int>(root)];
|
||||
HeapProfiler* profiler() { return profiler_; }
|
||||
HeapEntry* root() { return &entries_[root_index_]; }
|
||||
HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; }
|
||||
HeapEntry* gc_subroot(Root root) {
|
||||
return &entries_[gc_subroot_indexes_[static_cast<int>(root)]];
|
||||
}
|
||||
std::deque<HeapEntry>& entries() { return entries_; }
|
||||
std::vector<HeapEntry>& entries() { return entries_; }
|
||||
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_; }
|
||||
void RememberLastJSObjectId();
|
||||
SnapshotObjectId max_snapshot_js_object_id() const {
|
||||
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,
|
||||
const char* name,
|
||||
SnapshotObjectId id,
|
||||
@ -195,28 +202,28 @@ class HeapSnapshot {
|
||||
unsigned trace_node_id);
|
||||
void AddSyntheticRootEntries();
|
||||
HeapEntry* GetEntryById(SnapshotObjectId id);
|
||||
std::vector<HeapEntry*>* GetSortedEntriesList();
|
||||
void FillChildren();
|
||||
|
||||
void Print(int max_depth);
|
||||
|
||||
private:
|
||||
void AddRootEntry();
|
||||
void AddGcRootsEntry();
|
||||
void AddGcSubrootEntry(Root root, SnapshotObjectId id);
|
||||
HeapEntry* AddRootEntry();
|
||||
HeapEntry* AddGcRootsEntry();
|
||||
HeapEntry* AddGcSubrootEntry(Root root, SnapshotObjectId id);
|
||||
|
||||
HeapProfiler* profiler_;
|
||||
HeapEntry* root_entry_ = nullptr;
|
||||
HeapEntry* gc_roots_entry_ = nullptr;
|
||||
HeapEntry* gc_subroot_entries_[static_cast<int>(Root::kNumberOfRoots)];
|
||||
// For |entries_| we rely on the deque property, that it never reallocates
|
||||
// backing storage, thus all entry pointers remain valid for the duration
|
||||
// of snapshotting.
|
||||
std::deque<HeapEntry> entries_;
|
||||
int root_index_;
|
||||
int gc_roots_index_;
|
||||
int gc_subroot_indexes_[static_cast<int>(Root::kNumberOfRoots)];
|
||||
std::vector<HeapEntry> entries_;
|
||||
std::deque<HeapGraphEdge> edges_;
|
||||
std::vector<HeapGraphEdge*> children_;
|
||||
std::unordered_map<SnapshotObjectId, HeapEntry*> entries_by_id_cache_;
|
||||
std::deque<HeapGraphEdge*> children_;
|
||||
std::vector<HeapEntry*> sorted_entries_;
|
||||
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);
|
||||
};
|
||||
@ -334,81 +341,93 @@ class V8HeapExplorer : public HeapEntriesAllocator {
|
||||
|
||||
const char* GetSystemEntryName(HeapObject* object);
|
||||
|
||||
void ExtractLocation(HeapEntry* entry, HeapObject* object);
|
||||
void ExtractLocationForJSFunction(HeapEntry* entry, JSFunction* func);
|
||||
void ExtractReferences(HeapEntry* entry, HeapObject* obj);
|
||||
void ExtractJSGlobalProxyReferences(HeapEntry* entry, JSGlobalProxy* proxy);
|
||||
void ExtractJSObjectReferences(HeapEntry* entry, JSObject* js_obj);
|
||||
void ExtractStringReferences(HeapEntry* entry, String* obj);
|
||||
void ExtractSymbolReferences(HeapEntry* entry, Symbol* symbol);
|
||||
void ExtractJSCollectionReferences(HeapEntry* entry,
|
||||
JSCollection* collection);
|
||||
void ExtractJSWeakCollectionReferences(HeapEntry* entry,
|
||||
void ExtractLocation(int entry, HeapObject* object);
|
||||
void ExtractLocationForJSFunction(int entry, JSFunction* func);
|
||||
void ExtractReferences(int entry, HeapObject* obj);
|
||||
void ExtractJSGlobalProxyReferences(int entry, JSGlobalProxy* proxy);
|
||||
void ExtractJSObjectReferences(int entry, JSObject* js_obj);
|
||||
void ExtractStringReferences(int entry, String* obj);
|
||||
void ExtractSymbolReferences(int entry, Symbol* symbol);
|
||||
void ExtractJSCollectionReferences(int entry, JSCollection* collection);
|
||||
void ExtractJSWeakCollectionReferences(int entry,
|
||||
JSWeakCollection* collection);
|
||||
void ExtractEphemeronHashTableReferences(HeapEntry* entry,
|
||||
void ExtractEphemeronHashTableReferences(int entry,
|
||||
EphemeronHashTable* table);
|
||||
void ExtractContextReferences(HeapEntry* entry, Context* context);
|
||||
void ExtractMapReferences(HeapEntry* entry, Map* map);
|
||||
void ExtractSharedFunctionInfoReferences(HeapEntry* entry,
|
||||
void ExtractContextReferences(int entry, Context* context);
|
||||
void ExtractMapReferences(int entry, Map* map);
|
||||
void ExtractSharedFunctionInfoReferences(int entry,
|
||||
SharedFunctionInfo* shared);
|
||||
void ExtractScriptReferences(HeapEntry* entry, Script* script);
|
||||
void ExtractAccessorInfoReferences(HeapEntry* entry,
|
||||
AccessorInfo* accessor_info);
|
||||
void ExtractAccessorPairReferences(HeapEntry* entry, AccessorPair* accessors);
|
||||
void ExtractCodeReferences(HeapEntry* entry, Code* code);
|
||||
void ExtractCellReferences(HeapEntry* entry, Cell* cell);
|
||||
void ExtractFeedbackCellReferences(HeapEntry* entry,
|
||||
FeedbackCell* feedback_cell);
|
||||
void ExtractPropertyCellReferences(HeapEntry* entry, PropertyCell* cell);
|
||||
void ExtractAllocationSiteReferences(HeapEntry* entry, AllocationSite* site);
|
||||
void ExtractScriptReferences(int entry, Script* script);
|
||||
void ExtractAccessorInfoReferences(int entry, AccessorInfo* accessor_info);
|
||||
void ExtractAccessorPairReferences(int entry, AccessorPair* accessors);
|
||||
void ExtractCodeReferences(int entry, Code* code);
|
||||
void ExtractCellReferences(int entry, Cell* cell);
|
||||
void ExtractFeedbackCellReferences(int entry, FeedbackCell* feedback_cell);
|
||||
void ExtractPropertyCellReferences(int entry, PropertyCell* cell);
|
||||
void ExtractAllocationSiteReferences(int entry, AllocationSite* site);
|
||||
void ExtractArrayBoilerplateDescriptionReferences(
|
||||
HeapEntry* entry, ArrayBoilerplateDescription* value);
|
||||
void ExtractJSArrayBufferReferences(HeapEntry* entry, JSArrayBuffer* buffer);
|
||||
void ExtractJSPromiseReferences(HeapEntry* entry, JSPromise* promise);
|
||||
void ExtractJSGeneratorObjectReferences(HeapEntry* entry,
|
||||
int entry, ArrayBoilerplateDescription* value);
|
||||
void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer);
|
||||
void ExtractJSPromiseReferences(int entry, JSPromise* promise);
|
||||
void ExtractJSGeneratorObjectReferences(int entry,
|
||||
JSGeneratorObject* generator);
|
||||
void ExtractFixedArrayReferences(HeapEntry* entry, FixedArray* array);
|
||||
void ExtractFeedbackVectorReferences(HeapEntry* entry,
|
||||
void ExtractFixedArrayReferences(int entry, FixedArray* array);
|
||||
void ExtractFeedbackVectorReferences(int entry,
|
||||
FeedbackVector* feedback_vector);
|
||||
template <typename T>
|
||||
void ExtractWeakArrayReferences(int header_size, HeapEntry* entry, T* array);
|
||||
void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
|
||||
void ExtractAccessorPairProperty(JSObject* js_obj, HeapEntry* entry,
|
||||
Name* key, Object* callback_obj,
|
||||
int field_offset = -1);
|
||||
void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry);
|
||||
void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry);
|
||||
void ExtractWeakArrayReferences(int header_size, int entry, T* array);
|
||||
void ExtractPropertyReferences(JSObject* js_obj, int entry);
|
||||
void ExtractAccessorPairProperty(JSObject* js_obj, int entry, Name* key,
|
||||
Object* callback_obj, int field_offset = -1);
|
||||
void ExtractElementReferences(JSObject* js_obj, int entry);
|
||||
void ExtractInternalReferences(JSObject* js_obj, int entry);
|
||||
|
||||
bool IsEssentialObject(Object* object);
|
||||
bool IsEssentialHiddenReference(Object* parent, int field_offset);
|
||||
|
||||
void SetContextReference(HeapObject* parent_obj, HeapEntry* parent_entry,
|
||||
String* reference_name, Object* child,
|
||||
void SetContextReference(HeapObject* parent_obj,
|
||||
int parent,
|
||||
String* reference_name,
|
||||
Object* child,
|
||||
int field_offset);
|
||||
void SetNativeBindReference(HeapObject* parent_obj, HeapEntry* parent_entry,
|
||||
const char* reference_name, Object* child);
|
||||
void SetElementReference(HeapObject* parent_obj, HeapEntry* parent_entry,
|
||||
int index, Object* child);
|
||||
void SetInternalReference(HeapObject* parent_obj, HeapEntry* parent_entry,
|
||||
const char* reference_name, Object* child,
|
||||
void SetNativeBindReference(HeapObject* parent_obj,
|
||||
int parent,
|
||||
const char* reference_name,
|
||||
Object* child);
|
||||
void SetElementReference(HeapObject* parent_obj,
|
||||
int parent,
|
||||
int index,
|
||||
Object* child);
|
||||
void SetInternalReference(HeapObject* parent_obj,
|
||||
int parent,
|
||||
const char* reference_name,
|
||||
Object* child,
|
||||
int field_offset = -1);
|
||||
void SetInternalReference(HeapObject* parent_obj, HeapEntry* parent_entry,
|
||||
int index, Object* child, int field_offset = -1);
|
||||
void SetHiddenReference(HeapObject* parent_obj, HeapEntry* parent_entry,
|
||||
int index, Object* child, int field_offset);
|
||||
void SetWeakReference(HeapObject* parent_obj, HeapEntry* parent_entry,
|
||||
const char* reference_name, Object* child_obj,
|
||||
void SetInternalReference(HeapObject* parent_obj,
|
||||
int parent,
|
||||
int index,
|
||||
Object* child,
|
||||
int field_offset = -1);
|
||||
void SetHiddenReference(HeapObject* parent_obj, int parent, int index,
|
||||
Object* child, int field_offset);
|
||||
void SetWeakReference(HeapObject* parent_obj,
|
||||
int parent,
|
||||
const char* reference_name,
|
||||
Object* child_obj,
|
||||
int field_offset);
|
||||
void SetWeakReference(HeapObject* parent_obj, HeapEntry* parent_entry,
|
||||
int index, Object* child_obj, int field_offset);
|
||||
void SetPropertyReference(HeapObject* parent_obj, HeapEntry* parent_entry,
|
||||
void SetWeakReference(HeapObject* parent_obj,
|
||||
int parent,
|
||||
int index,
|
||||
Object* child_obj,
|
||||
int field_offset);
|
||||
void SetPropertyReference(HeapObject* parent_obj, int parent,
|
||||
Name* reference_name, Object* child,
|
||||
const char* name_format_string = nullptr,
|
||||
int field_offset = -1);
|
||||
void SetDataOrAccessorPropertyReference(
|
||||
PropertyKind kind, JSObject* parent_obj, HeapEntry* parent_entry,
|
||||
Name* reference_name, Object* child,
|
||||
const char* name_format_string = nullptr, int field_offset = -1);
|
||||
PropertyKind kind, JSObject* parent_obj, int parent, Name* reference_name,
|
||||
Object* child, const char* name_format_string = nullptr,
|
||||
int field_offset = -1);
|
||||
|
||||
void SetUserGlobalReference(Object* user_global);
|
||||
void SetRootGcRootsReference();
|
||||
@ -509,7 +528,7 @@ class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
|
||||
public:
|
||||
// The HeapEntriesMap instance is used to track a mapping between
|
||||
// real heap objects and their representations in heap snapshots.
|
||||
using HeapEntriesMap = std::unordered_map<HeapThing, HeapEntry*>;
|
||||
using HeapEntriesMap = std::unordered_map<HeapThing, int>;
|
||||
|
||||
HeapSnapshotGenerator(HeapSnapshot* snapshot,
|
||||
v8::ActivityControl* control,
|
||||
|
@ -157,9 +157,12 @@ static Optional<SourceLocation> GetLocation(const v8::HeapSnapshot* s,
|
||||
const v8::HeapGraphNode* node) {
|
||||
const i::HeapSnapshot* snapshot = reinterpret_cast<const i::HeapSnapshot*>(s);
|
||||
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) {
|
||||
if (loc.entry_index == entry->index()) {
|
||||
if (loc.entry_index == index) {
|
||||
return Optional<SourceLocation>(loc);
|
||||
}
|
||||
}
|
||||
@ -220,7 +223,7 @@ static bool ValidateSnapshot(const v8::HeapSnapshot* snapshot, int depth = 3) {
|
||||
entry->value = reinterpret_cast<void*>(ref_count + 1);
|
||||
}
|
||||
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) {
|
||||
v8::base::HashMap::Entry* map_entry = visited.Lookup(
|
||||
reinterpret_cast<void*>(&entry),
|
||||
@ -1000,6 +1003,21 @@ TEST(HeapEntryIdsAndGC) {
|
||||
CHECK_EQ(b1->GetId(), b2->GetId());
|
||||
}
|
||||
|
||||
|
||||
TEST(HeapSnapshotRootPreservedAfterSorting) {
|
||||
LocalContext env;
|
||||
v8::HandleScope scope(env->GetIsolate());
|
||||
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
|
||||
const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
|
||||
CHECK(ValidateSnapshot(snapshot));
|
||||
const v8::HeapGraphNode* root1 = snapshot->GetRoot();
|
||||
const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
|
||||
snapshot))->GetSortedEntriesList();
|
||||
const v8::HeapGraphNode* root2 = snapshot->GetRoot();
|
||||
CHECK_EQ(root1, root2);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class TestJSONStream : public v8::OutputStream {
|
||||
|
Loading…
Reference in New Issue
Block a user