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 |