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

This is a reland of 69a502ce5c

TBR=ulan@chromium.org

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}

Change-Id: I416da19eb38a1a55f5e2f5897062bc1ca454ac34
Reviewed-on: https://chromium-review.googlesource.com/1246802
Commit-Queue: Alexei Filippov <alph@chromium.org>
Reviewed-by: Alexei Filippov <alph@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56250}
This commit is contained in:
Alexei Filippov 2018-09-26 14:16:46 -07:00 committed by Commit Bot
parent e6d208b6a0
commit 181bbd5c88
4 changed files with 281 additions and 437 deletions

View File

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

View File

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

View File

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

View File

@ -157,12 +157,9 @@ 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 int index =
const_cast<i::HeapEntry*>(reinterpret_cast<const i::HeapEntry*>(node))
->index();
const i::HeapEntry* entry = reinterpret_cast<const i::HeapEntry*>(node);
for (const auto& loc : locations) {
if (loc.entry_index == index) {
if (loc.entry_index == entry->index()) {
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);
}
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) {
v8::base::HashMap::Entry* map_entry = visited.Lookup(
reinterpret_cast<void*>(&entry),
@ -1003,21 +1000,6 @@ TEST(HeapEntryIdsAndGC) {
CHECK_EQ(b1->GetId(), b2->GetId());
}
TEST(HeapSnapshotRootPreservedAfterSorting) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
CHECK(ValidateSnapshot(snapshot));
const v8::HeapGraphNode* root1 = snapshot->GetRoot();
const_cast<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 {