Chromium Code Reviews| Index: src/profile-generator.cc |
| diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
| index 5626acaba4bf7fc37c75921767c12c77a0cff172..78e8f894642eedd9842513573db182234c001932 100644 |
| --- a/src/profile-generator.cc |
| +++ b/src/profile-generator.cc |
| @@ -938,7 +938,7 @@ void HeapGraphEdge::Init( |
| void HeapGraphEdge::Init(int child_index, Type type, int index, HeapEntry* to) { |
| - ASSERT(type == kElement || type == kHidden); |
| + ASSERT(type == kElement || type == kHidden || type == kWeak); |
| child_index_ = child_index; |
| type_ = type; |
| index_ = index; |
| @@ -1053,8 +1053,11 @@ void HeapEntry::PaintAllReachable() { |
| } |
| -void HeapEntry::Print(int max_depth, int indent) { |
| - OS::Print("%6d %6d [%llu] ", self_size(), RetainedSize(false), id()); |
| +void HeapEntry::Print( |
| + const char* prefix, const char* edge_name, int max_depth, int indent) { |
| + OS::Print("%6d %7d @%6llu %*c %s%s: ", |
| + self_size(), RetainedSize(false), id(), |
| + indent, ' ', prefix, edge_name); |
| if (type() != kString) { |
| OS::Print("%s %.40s\n", TypeAsString(), name_); |
| } else { |
| @@ -1073,29 +1076,40 @@ void HeapEntry::Print(int max_depth, int indent) { |
| Vector<HeapGraphEdge> ch = children(); |
| for (int i = 0; i < ch.length(); ++i) { |
| HeapGraphEdge& edge = ch[i]; |
| + const char* edge_prefix = ""; |
| + ScopedVector<char> index(64); |
| + const char* edge_name = index.start(); |
| switch (edge.type()) { |
| case HeapGraphEdge::kContextVariable: |
| - OS::Print(" %*c #%s: ", indent, ' ', edge.name()); |
| + edge_prefix = "#"; |
| + edge_name = edge.name(); |
| break; |
| case HeapGraphEdge::kElement: |
| - OS::Print(" %*c %d: ", indent, ' ', edge.index()); |
| + OS::SNPrintF(index, "%d", edge.index()); |
| break; |
| case HeapGraphEdge::kInternal: |
| - OS::Print(" %*c $%s: ", indent, ' ', edge.name()); |
| + edge_prefix = "$"; |
| + edge_name = edge.name(); |
| break; |
| case HeapGraphEdge::kProperty: |
| - OS::Print(" %*c %s: ", indent, ' ', edge.name()); |
| + edge_name = edge.name(); |
| break; |
| case HeapGraphEdge::kHidden: |
| - OS::Print(" %*c $%d: ", indent, ' ', edge.index()); |
| + edge_prefix = "$"; |
| + OS::SNPrintF(index, "%d", edge.index()); |
| break; |
| case HeapGraphEdge::kShortcut: |
| - OS::Print(" %*c ^%s: ", indent, ' ', edge.name()); |
| + edge_prefix = "^"; |
| + edge_name = edge.name(); |
| + break; |
| + case HeapGraphEdge::kWeak: |
| + edge_prefix = "w"; |
| + OS::SNPrintF(index, "%d", edge.index()); |
| break; |
| default: |
| - OS::Print("!!! unknown edge type: %d ", edge.type()); |
| + OS::SNPrintF(index, "!!! unknown edge type: %d ", edge.type()); |
| } |
| - edge.to()->Print(max_depth, indent + 2); |
| + edge.to()->Print(edge_prefix, edge_name, max_depth, indent + 2); |
| } |
| } |
| @@ -1215,6 +1229,8 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, |
| STATIC_ASSERT( |
| sizeof(HeapEntry) == |
| SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize); // NOLINT |
| + for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) |
|
Vitaly Repeshko
2011/12/02 23:39:47
nit: {}
mnaganov (inactive)
2011/12/05 12:55:25
Done.
|
| + gc_subroot_entries_[i] = NULL; |
| } |
| HeapSnapshot::~HeapSnapshot() { |
| @@ -1270,6 +1286,21 @@ HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count, |
| } |
| +HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag, |
| + int children_count, |
| + int retainers_count) { |
| + ASSERT(gc_subroot_entries_[tag] == NULL); |
| + ASSERT(0 <= tag && tag < VisitorSynchronization::kNumberOfSyncTags); |
| + return (gc_subroot_entries_[tag] = AddEntry( |
| + HeapEntry::kObject, |
| + VisitorSynchronization::kTagNames[tag], |
| + HeapObjectsMap::GetNthGcSubrootId(tag), |
| + 0, |
| + children_count, |
| + retainers_count)); |
| +} |
| + |
| + |
| HeapEntry* HeapSnapshot::AddNativesRootEntry(int children_count, |
| int retainers_count) { |
| ASSERT(natives_root_entry_ == NULL); |
| @@ -1355,17 +1386,22 @@ List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { |
| void HeapSnapshot::Print(int max_depth) { |
| - root()->Print(max_depth, 0); |
| + root()->Print("", "", max_depth, 0); |
| } |
| // We split IDs on evens for embedder objects (see |
| // HeapObjectsMap::GenerateId) and odds for native objects. |
| const uint64_t HeapObjectsMap::kInternalRootObjectId = 1; |
| -const uint64_t HeapObjectsMap::kGcRootsObjectId = 3; |
| -const uint64_t HeapObjectsMap::kNativesRootObjectId = 5; |
| -// Increase kFirstAvailableObjectId if new 'special' objects appear. |
| -const uint64_t HeapObjectsMap::kFirstAvailableObjectId = 7; |
| +const uint64_t HeapObjectsMap::kGcRootsObjectId = |
| + HeapObjectsMap::kInternalRootObjectId + HeapObjectsMap::kObjectIdStep; |
| +const uint64_t HeapObjectsMap::kNativesRootObjectId = |
| + HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep; |
| +const uint64_t HeapObjectsMap::kGcRootsFirstSubrootId = |
| + HeapObjectsMap::kNativesRootObjectId + HeapObjectsMap::kObjectIdStep; |
| +const uint64_t HeapObjectsMap::kFirstAvailableObjectId = |
| + HeapObjectsMap::kGcRootsFirstSubrootId + |
| + VisitorSynchronization::kNumberOfSyncTags * HeapObjectsMap::kObjectIdStep; |
| HeapObjectsMap::HeapObjectsMap() |
| : initial_fill_mode_(true), |
| @@ -1391,7 +1427,7 @@ uint64_t HeapObjectsMap::FindObject(Address addr) { |
| if (existing != 0) return existing; |
| } |
| uint64_t id = next_id_; |
| - next_id_ += 2; |
| + next_id_ += kObjectIdStep; |
| AddEntry(addr, id); |
| return id; |
| } |
| @@ -1684,6 +1720,12 @@ HeapObject *const V8HeapExplorer::kInternalRootObject = |
| HeapObject *const V8HeapExplorer::kGcRootsObject = |
| reinterpret_cast<HeapObject*>( |
| static_cast<intptr_t>(HeapObjectsMap::kGcRootsObjectId)); |
| +HeapObject *const V8HeapExplorer::kFirstGcSubrootObject = |
| + reinterpret_cast<HeapObject*>( |
| + static_cast<intptr_t>(HeapObjectsMap::kGcRootsFirstSubrootId)); |
| +HeapObject *const V8HeapExplorer::kLastGcSubrootObject = |
| + reinterpret_cast<HeapObject*>( |
| + static_cast<intptr_t>(HeapObjectsMap::kFirstAvailableObjectId)); |
| V8HeapExplorer::V8HeapExplorer( |
| @@ -1716,6 +1758,11 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
| return snapshot_->AddRootEntry(children_count); |
| } else if (object == kGcRootsObject) { |
| return snapshot_->AddGcRootsEntry(children_count, retainers_count); |
| + } else if (object >= kFirstGcSubrootObject && object < kLastGcSubrootObject) { |
| + return snapshot_->AddGcSubrootEntry( |
| + GetGcSubrootOrder(object), |
| + children_count, |
| + retainers_count); |
| } else if (object->IsJSGlobalObject()) { |
| const char* tag = objects_tags_.GetTag(object); |
| const char* name = collection_->names()->GetName( |
| @@ -1779,6 +1826,18 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
| : "", |
| children_count, |
| retainers_count); |
| + } else if (object->IsGlobalContext()) { |
| + return AddEntry(object, |
| + HeapEntry::kHidden, |
| + "system / GlobalContext", |
| + children_count, |
| + retainers_count); |
| + } else if (object->IsContext()) { |
| + return AddEntry(object, |
| + HeapEntry::kHidden, |
| + "system / Context", |
| + children_count, |
| + retainers_count); |
| } else if (object->IsFixedArray() || |
| object->IsFixedDoubleArray() || |
| object->IsByteArray() || |
| @@ -1818,9 +1877,37 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
| } |
| +class GcSubrootsEnumerator : public ObjectVisitor { |
| + public: |
| + GcSubrootsEnumerator( |
| + SnapshotFillerInterface* filler, V8HeapExplorer* explorer) |
| + : filler_(filler), |
| + explorer_(explorer), |
| + previous_object_count_(0), |
| + object_count_(0) { |
| + } |
| + void VisitPointers(Object** start, Object** end) { |
| + object_count_ += end - start; |
|
Vitaly Repeshko
2011/12/02 23:39:47
Will this require a follow up "Fix win64 build"? :
mnaganov (inactive)
2011/12/05 12:55:25
Thanks. I forgot about this disaster.
|
| + } |
| + void Synchronize(VisitorSynchronization::SyncTag tag) { |
| + // Skip empty subroots. |
| + if (previous_object_count_ != object_count_) { |
| + previous_object_count_ = object_count_; |
| + filler_->AddEntry(V8HeapExplorer::GetNthGcSubrootObject(tag), explorer_); |
| + } |
| + } |
| + private: |
| + SnapshotFillerInterface* filler_; |
| + V8HeapExplorer* explorer_; |
| + int previous_object_count_; |
| + int object_count_; |
| +}; |
| + |
|
Vitaly Repeshko
2011/12/02 23:39:47
nit: Insert one more blank line.
mnaganov (inactive)
2011/12/05 12:55:25
Done.
|
| void V8HeapExplorer::AddRootEntries(SnapshotFillerInterface* filler) { |
| filler->AddEntry(kInternalRootObject, this); |
| filler->AddEntry(kGcRootsObject, this); |
| + GcSubrootsEnumerator enumerator(filler, this); |
| + heap_->IterateRoots(&enumerator, VISIT_ALL); |
| } |
| @@ -1939,6 +2026,11 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
| "literals_or_bindings", |
| js_fun->literals_or_bindings(), |
| JSFunction::kLiteralsOffset); |
| + for (int i = JSFunction::kNonWeakFieldsEndOffset; |
| + i < JSFunction::kSize; |
| + i += kPointerSize) { |
| + SetWeakReference(js_fun, entry, i, *HeapObject::RawField(js_fun, i), i); |
| + } |
| } |
| TagObject(js_obj->properties(), "(object properties)"); |
| SetInternalReference(obj, entry, |
| @@ -1965,8 +2057,14 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
| "(context func. result caches)"); |
| TagObject(context->normalized_map_cache(), "(context norm. map cache)"); |
| TagObject(context->runtime_context(), "(runtime context)"); |
| - TagObject(context->map_cache(), "(context map cache)"); |
| TagObject(context->data(), "(context data)"); |
| + for (int i = Context::FIRST_WEAK_SLOT; |
| + i < Context::GLOBAL_CONTEXT_SLOTS; |
| + ++i) { |
| + SetWeakReference(obj, entry, |
| + i, context->get(i), |
| + FixedArray::OffsetOfElementAt(i)); |
| + } |
| } else if (obj->IsMap()) { |
| Map* map = Map::cast(obj); |
| SetInternalReference(obj, entry, |
| @@ -2009,6 +2107,9 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
| SetInternalReference(obj, entry, |
| "script", shared->script(), |
| SharedFunctionInfo::kScriptOffset); |
| + SetWeakReference(obj, entry, |
| + 1, shared->initial_map(), |
| + SharedFunctionInfo::kInitialMapOffset); |
| } else if (obj->IsScript()) { |
| Script* script = Script::cast(obj); |
| SetInternalReference(obj, entry, |
| @@ -2236,14 +2337,63 @@ HeapEntry* V8HeapExplorer::GetEntry(Object* obj) { |
| class RootsReferencesExtractor : public ObjectVisitor { |
|
Vitaly Repeshko
2011/12/02 23:39:47
nit: Consider adding more vertical whitespace to t
mnaganov (inactive)
2011/12/05 12:55:25
Done.
|
| public: |
| - explicit RootsReferencesExtractor(V8HeapExplorer* explorer) |
| - : explorer_(explorer) { |
| + struct IndexTag { |
|
Vitaly Repeshko
2011/12/02 23:39:47
Can be private.
mnaganov (inactive)
2011/12/05 12:55:25
Done.
|
| + IndexTag(int index, VisitorSynchronization::SyncTag tag) |
| + : index(index), tag(tag) { } |
| + int index; |
| + VisitorSynchronization::SyncTag tag; |
| + }; |
| + RootsReferencesExtractor() |
| + : collecting_all_references_(false), |
| + previous_reference_count_(0) { |
| } |
| void VisitPointers(Object** start, Object** end) { |
| - for (Object** p = start; p < end; p++) explorer_->SetGcRootsReference(*p); |
| + if (collecting_all_references_) { |
| + for (Object** p = start; p < end; p++) all_references_.Add(*p); |
| + } else { |
| + for (Object** p = start; p < end; p++) strong_references_.Add(*p); |
| + } |
| + } |
| + void SetCollectingAllReferences() { collecting_all_references_ = true; } |
| + void FillReferences(V8HeapExplorer* explorer) { |
| + for (int i = 0; i < reference_tags_.length(); ++i) { |
| + explorer->SetGcRootsReference(reference_tags_[i].tag); |
| + } |
| + int strong_index = 0, all_index = 0, tags_index = 0; |
| + while (strong_index < strong_references_.length()) { |
|
Vitaly Repeshko
2011/12/02 23:39:47
You can have a single loop here (over all referenc
mnaganov (inactive)
2011/12/05 12:55:25
Right. I had this in mind but then forgot. Fixed.
|
| + if (strong_references_[strong_index] == all_references_[all_index]) { |
| + explorer->SetGcSubrootReference(reference_tags_[tags_index].tag, |
| + false, |
| + all_references_[all_index++]); |
| + ++strong_index; |
| + } else { |
| + explorer->SetGcSubrootReference(reference_tags_[tags_index].tag, |
|
Vitaly Repeshko
2011/12/02 23:39:47
Hmm, actually, are you sure this loop terminates i
mnaganov (inactive)
2011/12/05 12:55:25
Yes. strong_references_ is a subset of all_referen
|
| + true, |
| + all_references_[all_index++]); |
| + } |
| + if (reference_tags_[tags_index].index == all_index) ++tags_index; |
| + } |
| + while (all_index < all_references_.length()) { |
| + explorer->SetGcSubrootReference(reference_tags_[tags_index].tag, |
| + true, |
| + all_references_[all_index++]); |
| + if (reference_tags_[tags_index].index == all_index) ++tags_index; |
| + } |
|
Vitaly Repeshko
2011/12/02 23:39:47
ASSERT(strong_index <= all_index)?
mnaganov (inactive)
2011/12/05 12:55:25
Added to the beginning:
ASSERT(strong_references_
|
| } |
| + void Synchronize(VisitorSynchronization::SyncTag tag) { |
| + if (collecting_all_references_ && |
| + previous_reference_count_ != all_references_.length()) { |
| + previous_reference_count_ = all_references_.length(); |
| + reference_tags_.Add(IndexTag(previous_reference_count_, tag)); |
| + } |
| + } |
| + |
| private: |
| - V8HeapExplorer* explorer_; |
| + bool collecting_all_references_; |
| + List<Object*> strong_references_; |
| + List<Object*> all_references_; |
| + int previous_reference_count_; |
| + List<IndexTag> reference_tags_; |
| }; |
| @@ -2268,8 +2418,11 @@ bool V8HeapExplorer::IterateAndExtractReferences( |
| return false; |
| } |
| SetRootGcRootsReference(); |
| - RootsReferencesExtractor extractor(this); |
| + RootsReferencesExtractor extractor; |
| + heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG); |
| + extractor.SetCollectingAllReferences(); |
| heap_->IterateRoots(&extractor, VISIT_ALL); |
| + extractor.FillReferences(this); |
| filler_ = NULL; |
| return progress_->ProgressReport(false); |
| } |
| @@ -2359,6 +2512,24 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, |
| } |
| +void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, |
| + HeapEntry* parent_entry, |
| + int index, |
| + Object* child_obj, |
| + int field_offset) { |
| + HeapEntry* child_entry = GetEntry(child_obj); |
| + if (child_entry != NULL) { |
| + filler_->SetIndexedReference(HeapGraphEdge::kWeak, |
| + parent_obj, |
| + parent_entry, |
| + index, |
| + child_obj, |
| + child_entry); |
| + IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); |
| + } |
| +} |
| + |
| + |
| void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, |
| HeapEntry* parent_entry, |
| String* reference_name, |
| @@ -2421,12 +2592,21 @@ void V8HeapExplorer::SetRootShortcutReference(Object* child_obj) { |
| } |
| -void V8HeapExplorer::SetGcRootsReference(Object* child_obj) { |
| +void V8HeapExplorer::SetGcRootsReference(VisitorSynchronization::SyncTag tag) { |
| + filler_->SetIndexedAutoIndexReference( |
| + HeapGraphEdge::kElement, |
| + kGcRootsObject, snapshot_->gc_roots(), |
| + GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag)); |
| +} |
| + |
| + |
| +void V8HeapExplorer::SetGcSubrootReference( |
| + VisitorSynchronization::SyncTag tag, bool is_weak, Object* child_obj) { |
| HeapEntry* child_entry = GetEntry(child_obj); |
| if (child_entry != NULL) { |
| filler_->SetIndexedAutoIndexReference( |
| - HeapGraphEdge::kElement, |
| - kGcRootsObject, snapshot_->gc_roots(), |
| + is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kElement, |
| + GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag), |
| child_obj, child_entry); |
| } |
| } |
| @@ -3235,7 +3415,8 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) { |
| writer_->AddNumber(edge->type()); |
| writer_->AddCharacter(','); |
| if (edge->type() == HeapGraphEdge::kElement |
| - || edge->type() == HeapGraphEdge::kHidden) { |
| + || edge->type() == HeapGraphEdge::kHidden |
| + || edge->type() == HeapGraphEdge::kWeak) { |
| writer_->AddNumber(edge->index()); |
| } else { |
| writer_->AddNumber(GetStringId(edge->name())); |
| @@ -3315,7 +3496,8 @@ void HeapSnapshotJSONSerializer::SerializeNodes() { |
| "," JSON_S("property") |
| "," JSON_S("internal") |
| "," JSON_S("hidden") |
| - "," JSON_S("shortcut")) |
| + "," JSON_S("shortcut") |
| + "," JSON_S("weak")) |
| "," JSON_S("string_or_number") |
| "," JSON_S("node")))))); |
| #undef JSON_S |