Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Unified Diff: src/profile-generator.cc

Issue 5274002: Version 2.5.8... (Closed) Base URL: http://v8.googlecode.com/svn/trunk/
Patch Set: Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/profile-generator.h ('k') | src/profile-generator-inl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/profile-generator.cc
===================================================================
--- src/profile-generator.cc (revision 5873)
+++ src/profile-generator.cc (working copy)
@@ -829,7 +829,10 @@
void HeapGraphEdge::Init(
int child_index, Type type, const char* name, HeapEntry* to) {
- ASSERT(type == kContextVariable || type == kProperty || type == kInternal);
+ ASSERT(type == kContextVariable
+ || type == kProperty
+ || type == kInternal
+ || type == kShortcut);
child_index_ = child_index;
type_ = type;
name_ = name;
@@ -837,14 +840,20 @@
}
-void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) {
+void HeapGraphEdge::Init(int child_index, Type type, int index, HeapEntry* to) {
+ ASSERT(type == kElement || type == kHidden);
child_index_ = child_index;
- type_ = kElement;
+ type_ = type;
index_ = index;
to_ = to;
}
+void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) {
+ Init(child_index, kElement, index, to);
+}
+
+
HeapEntry* HeapGraphEdge::From() {
return reinterpret_cast<HeapEntry*>(this - child_index_) - 1;
}
@@ -860,12 +869,18 @@
snapshot_ = snapshot;
type_ = type;
painted_ = kUnpainted;
- calculated_data_index_ = kNoCalculatedData;
name_ = name;
- id_ = id;
self_size_ = self_size;
+ retained_size_ = 0;
children_count_ = children_count;
retainers_count_ = retainers_count;
+ dominator_ = NULL;
+
+ union {
+ uint64_t set_id;
+ Id stored_id;
+ } id_adaptor = {id};
+ id_ = id_adaptor.stored_id;
}
@@ -879,9 +894,12 @@
}
-void HeapEntry::SetElementReference(
- int child_index, int index, HeapEntry* entry, int retainer_index) {
- children_arr()[child_index].Init(child_index, index, entry);
+void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
+ int child_index,
+ int index,
+ HeapEntry* entry,
+ int retainer_index) {
+ children_arr()[child_index].Init(child_index, type, index, entry);
entry->retainers_arr()[retainer_index] = children_arr() + child_index;
}
@@ -892,30 +910,16 @@
}
-int HeapEntry::ReachableSize() {
- if (calculated_data_index_ == kNoCalculatedData) {
- calculated_data_index_ = snapshot_->AddCalculatedData();
+int HeapEntry::RetainedSize(bool exact) {
+ if (exact && (retained_size_ & kExactRetainedSizeTag) == 0) {
+ CalculateExactRetainedSize();
}
- return snapshot_->GetCalculatedData(
- calculated_data_index_).ReachableSize(this);
+ return retained_size_ & (~kExactRetainedSizeTag);
}
-int HeapEntry::RetainedSize() {
- if (calculated_data_index_ == kNoCalculatedData) {
- calculated_data_index_ = snapshot_->AddCalculatedData();
- }
- return snapshot_->GetCalculatedData(
- calculated_data_index_).RetainedSize(this);
-}
-
-
List<HeapGraphPath*>* HeapEntry::GetRetainingPaths() {
- if (calculated_data_index_ == kNoCalculatedData) {
- calculated_data_index_ = snapshot_->AddCalculatedData();
- }
- return snapshot_->GetCalculatedData(
- calculated_data_index_).GetRetainingPaths(this);
+ return snapshot_->GetRetainingPaths(this);
}
@@ -929,6 +933,7 @@
HeapEntry* entry = list.RemoveLast();
Vector<HeapGraphEdge> children = entry->children();
for (int i = 0; i < children.length(); ++i) {
+ if (children[i].type() == HeapGraphEdge::kShortcut) continue;
HeapEntry* child = children[i].to();
if (!child->painted_reachable()) {
list.Add(child);
@@ -952,8 +957,7 @@
void HeapEntry::Print(int max_depth, int indent) {
- OS::Print("%6d %6d %6d [%llu] ",
- self_size(), ReachableSize(), RetainedSize(), id_);
+ OS::Print("%6d %6d [%llu] ", self_size(), RetainedSize(false), id());
if (type() != kString) {
OS::Print("%s %.40s\n", TypeAsString(), name_);
} else {
@@ -985,6 +989,12 @@
case HeapGraphEdge::kProperty:
OS::Print(" %*c %s: ", indent, ' ', edge.name());
break;
+ case HeapGraphEdge::kHidden:
+ OS::Print(" %*c $%d: ", indent, ' ', edge.index());
+ break;
+ case HeapGraphEdge::kShortcut:
+ OS::Print(" %*c ^%s: ", indent, ' ', edge.name());
+ break;
default:
OS::Print("!!! unknown edge type: %d ", edge.type());
}
@@ -995,7 +1005,7 @@
const char* HeapEntry::TypeAsString() {
switch (type()) {
- case kInternal: return "/internal/";
+ case kHidden: return "/hidden/";
case kObject: return "/object/";
case kClosure: return "/closure/";
case kString: return "/string/";
@@ -1017,44 +1027,6 @@
}
-static void DeleteHeapGraphPath(HeapGraphPath** path_ptr) {
- delete *path_ptr;
-}
-
-void HeapEntryCalculatedData::Dispose() {
- if (retaining_paths_ != NULL) retaining_paths_->Iterate(DeleteHeapGraphPath);
- delete retaining_paths_;
-}
-
-
-int HeapEntryCalculatedData::ReachableSize(HeapEntry* entry) {
- if (reachable_size_ == kUnknownSize) CalculateSizes(entry);
- return reachable_size_;
-}
-
-
-int HeapEntryCalculatedData::RetainedSize(HeapEntry* entry) {
- if (retained_size_ == kUnknownSize) CalculateSizes(entry);
- return retained_size_;
-}
-
-
-class ReachableSizeCalculator {
- public:
- ReachableSizeCalculator()
- : reachable_size_(0) {
- }
-
- int reachable_size() const { return reachable_size_; }
-
- void Apply(HeapEntry* entry) {
- reachable_size_ += entry->self_size();
- }
-
- private:
- int reachable_size_;
-};
-
class RetainedSizeCalculator {
public:
RetainedSizeCalculator()
@@ -1073,20 +1045,17 @@
int retained_size_;
};
-void HeapEntryCalculatedData::CalculateSizes(HeapEntry* entry) {
+void HeapEntry::CalculateExactRetainedSize() {
// To calculate retained size, first we paint all reachable nodes in
- // one color (and calculate reachable size as a byproduct), then we
- // paint (or re-paint) all nodes reachable from other nodes with a
- // different color. Then we consider only nodes painted with the
- // first color for calculating the retained size.
- entry->snapshot()->ClearPaint();
- ReachableSizeCalculator rch_size_calc;
- entry->ApplyAndPaintAllReachable(&rch_size_calc);
- reachable_size_ = rch_size_calc.reachable_size();
+ // one color, then we paint (or re-paint) all nodes reachable from
+ // other nodes with a different color. Then we sum up self sizes of
+ // nodes painted with the first color.
+ snapshot()->ClearPaint();
+ PaintAllReachable();
List<HeapEntry*> list(10);
- HeapEntry* root = entry->snapshot()->root();
- if (entry != root) {
+ HeapEntry* root = snapshot()->root();
+ if (this != root) {
list.Add(root);
root->paint_reachable_from_others();
}
@@ -1094,8 +1063,9 @@
HeapEntry* curr = list.RemoveLast();
Vector<HeapGraphEdge> children = curr->children();
for (int i = 0; i < children.length(); ++i) {
+ if (children[i].type() == HeapGraphEdge::kShortcut) continue;
HeapEntry* child = children[i].to();
- if (child != entry && child->not_painted_reachable_from_others()) {
+ if (child != this && child->not_painted_reachable_from_others()) {
list.Add(child);
child->paint_reachable_from_others();
}
@@ -1103,8 +1073,10 @@
}
RetainedSizeCalculator ret_size_calc;
- entry->snapshot()->IterateEntries(&ret_size_calc);
+ snapshot()->IterateEntries(&ret_size_calc);
retained_size_ = ret_size_calc.reained_size();
+ ASSERT((retained_size_ & kExactRetainedSizeTag) == 0);
+ retained_size_ |= kExactRetainedSizeTag;
}
@@ -1142,32 +1114,28 @@
};
-List<HeapGraphPath*>* HeapEntryCalculatedData::GetRetainingPaths(
- HeapEntry* entry) {
- if (retaining_paths_ == NULL) retaining_paths_ = new List<HeapGraphPath*>(4);
- if (retaining_paths_->length() == 0 && entry->retainers().length() != 0) {
- CachedHeapGraphPath path;
- FindRetainingPaths(entry, &path);
- }
- return retaining_paths_;
+List<HeapGraphPath*>* HeapEntry::CalculateRetainingPaths() {
+ List<HeapGraphPath*>* retaining_paths = new List<HeapGraphPath*>(4);
+ CachedHeapGraphPath path;
+ FindRetainingPaths(&path, retaining_paths);
+ return retaining_paths;
}
-void HeapEntryCalculatedData::FindRetainingPaths(
- HeapEntry* entry,
- CachedHeapGraphPath* prev_path) {
- Vector<HeapGraphEdge*> retainers = entry->retainers();
- for (int i = 0; i < retainers.length(); ++i) {
- HeapGraphEdge* ret_edge = retainers[i];
+void HeapEntry::FindRetainingPaths(CachedHeapGraphPath* prev_path,
+ List<HeapGraphPath*>* retaining_paths) {
+ Vector<HeapGraphEdge*> rets = retainers();
+ for (int i = 0; i < rets.length(); ++i) {
+ HeapGraphEdge* ret_edge = rets[i];
if (prev_path->ContainsNode(ret_edge->From())) continue;
- if (ret_edge->From() != entry->snapshot()->root()) {
+ if (ret_edge->From() != snapshot()->root()) {
CachedHeapGraphPath path(*prev_path);
path.Add(ret_edge);
- FindRetainingPaths(ret_edge->From(), &path);
+ ret_edge->From()->FindRetainingPaths(&path, retaining_paths);
} else {
HeapGraphPath* ret_path = new HeapGraphPath(*prev_path->path());
ret_path->Set(0, ret_edge);
- retaining_paths_->Add(ret_path);
+ retaining_paths->Add(ret_path);
}
}
}
@@ -1192,6 +1160,7 @@
OS::Print("[#%s] ", edge->name());
break;
case HeapGraphEdge::kElement:
+ case HeapGraphEdge::kHidden:
OS::Print("[%d] ", edge->index());
break;
case HeapGraphEdge::kInternal:
@@ -1200,6 +1169,9 @@
case HeapGraphEdge::kProperty:
OS::Print("[%s] ", edge->name());
break;
+ case HeapGraphEdge::kShortcut:
+ OS::Print("[^%s] ", edge->name());
+ break;
default:
OS::Print("!!! unknown edge type: %d ", edge->type());
}
@@ -1211,6 +1183,8 @@
HeapObject *const HeapSnapshot::kInternalRootObject =
reinterpret_cast<HeapObject*>(1);
+HeapObject *const HeapSnapshot::kGcRootsObject =
+ reinterpret_cast<HeapObject*>(2);
// It is very important to keep objects that form a heap snapshot
@@ -1221,12 +1195,12 @@
template <> struct SnapshotSizeConstants<4> {
static const int kExpectedHeapGraphEdgeSize = 12;
- static const int kExpectedHeapEntrySize = 32;
+ static const int kExpectedHeapEntrySize = 36;
};
template <> struct SnapshotSizeConstants<8> {
static const int kExpectedHeapGraphEdgeSize = 24;
- static const int kExpectedHeapEntrySize = 40;
+ static const int kExpectedHeapEntrySize = 48;
};
} // namespace
@@ -1240,8 +1214,10 @@
title_(title),
uid_(uid),
root_entry_(NULL),
+ gc_roots_entry_(NULL),
raw_entries_(NULL),
- entries_sorted_(false) {
+ entries_sorted_(false),
+ retaining_paths_(HeapEntry::Match) {
STATIC_ASSERT(
sizeof(HeapGraphEdge) ==
SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapGraphEdgeSize); // NOLINT
@@ -1251,13 +1227,20 @@
}
-static void DisposeCalculatedData(HeapEntryCalculatedData* cdata) {
- cdata->Dispose();
+static void DeleteHeapGraphPath(HeapGraphPath** path_ptr) {
+ delete *path_ptr;
}
HeapSnapshot::~HeapSnapshot() {
DeleteArray(raw_entries_);
- calculated_data_.Iterate(DisposeCalculatedData);
+ for (HashMap::Entry* p = retaining_paths_.Start();
+ p != NULL;
+ p = retaining_paths_.Next(p)) {
+ List<HeapGraphPath*>* list =
+ reinterpret_cast<List<HeapGraphPath*>*>(p->value);
+ list->Iterate(DeleteHeapGraphPath);
+ delete list;
+ }
}
@@ -1280,9 +1263,20 @@
if (object == kInternalRootObject) {
ASSERT(root_entry_ == NULL);
ASSERT(retainers_count == 0);
- root_entry_ = AddEntry(
- HeapEntry::kInternal, "", 0, 0, children_count, retainers_count);
- return root_entry_;
+ return (root_entry_ = AddEntry(HeapEntry::kObject,
+ "",
+ HeapObjectsMap::kInternalRootObjectId,
+ 0,
+ children_count,
+ retainers_count));
+ } else if (object == kGcRootsObject) {
+ ASSERT(gc_roots_entry_ == NULL);
+ return (gc_roots_entry_ = AddEntry(HeapEntry::kObject,
+ "(GC roots)",
+ HeapObjectsMap::kGcRootsObjectId,
+ 0,
+ children_count,
+ retainers_count));
} else if (object->IsJSFunction()) {
JSFunction* func = JSFunction::cast(object);
SharedFunctionInfo* shared = func->shared();
@@ -1345,25 +1339,14 @@
children_count,
retainers_count);
}
- // No interest in this object.
- return NULL;
+ return AddEntry(object,
+ HeapEntry::kHidden,
+ "system",
+ children_count,
+ retainers_count);
}
-bool HeapSnapshot::WillAddEntry(HeapObject* object) {
- return object == kInternalRootObject
- || object->IsJSFunction()
- || object->IsJSRegExp()
- || object->IsJSObject()
- || object->IsString()
- || object->IsCode()
- || object->IsSharedFunctionInfo()
- || object->IsScript()
- || object->IsFixedArray()
- || object->IsHeapNumber();
-}
-
-
static void HeapEntryClearPaint(HeapEntry** entry_ptr) {
(*entry_ptr)->clear_paint();
}
@@ -1373,12 +1356,6 @@
}
-int HeapSnapshot::AddCalculatedData() {
- calculated_data_.Add(HeapEntryCalculatedData());
- return calculated_data_.length() - 1;
-}
-
-
HeapEntry* HeapSnapshot::AddEntry(HeapObject* object,
HeapEntry::Type type,
const char* name,
@@ -1387,7 +1364,7 @@
return AddEntry(type,
name,
collection_->GetObjectId(object->address()),
- GetObjectSize(object),
+ object->Size(),
children_count,
retainers_count);
}
@@ -1405,6 +1382,144 @@
}
+void HeapSnapshot::FillReversePostorderIndexes(Vector<HeapEntry*>* entries) {
+ ClearPaint();
+ int current_entry = 0;
+ List<HeapEntry*> nodes_to_visit;
+ nodes_to_visit.Add(root());
+ root()->paint_reachable();
+ while (!nodes_to_visit.is_empty()) {
+ HeapEntry* entry = nodes_to_visit.last();
+ Vector<HeapGraphEdge> children = entry->children();
+ bool has_new_edges = false;
+ for (int i = 0; i < children.length(); ++i) {
+ if (children[i].type() == HeapGraphEdge::kShortcut) continue;
+ HeapEntry* child = children[i].to();
+ if (!child->painted_reachable()) {
+ nodes_to_visit.Add(child);
+ child->paint_reachable();
+ has_new_edges = true;
+ }
+ }
+ if (!has_new_edges) {
+ entry->set_ordered_index(current_entry);
+ entries->at(current_entry++) = entry;
+ nodes_to_visit.RemoveLast();
+ }
+ }
+ entries->Truncate(current_entry);
+}
+
+
+static int Intersect(int i1, int i2, const Vector<HeapEntry*>& dominators) {
+ int finger1 = i1, finger2 = i2;
+ while (finger1 != finger2) {
+ while (finger1 < finger2) finger1 = dominators[finger1]->ordered_index();
+ while (finger2 < finger1) finger2 = dominators[finger2]->ordered_index();
+ }
+ return finger1;
+}
+
+// The algorithm is based on the article:
+// K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm"
+// Softw. Pract. Exper. 4 (2001), pp. 1–10.
+void HeapSnapshot::BuildDominatorTree(const Vector<HeapEntry*>& entries,
+ Vector<HeapEntry*>* dominators) {
+ if (entries.length() == 0) return;
+ const int root_index = entries.length() - 1;
+ for (int i = 0; i < root_index; ++i) dominators->at(i) = NULL;
+ dominators->at(root_index) = entries[root_index];
+ bool changed = true;
+ while (changed) {
+ changed = false;
+ for (int i = root_index - 1; i >= 0; --i) {
+ HeapEntry* new_idom = NULL;
+ Vector<HeapGraphEdge*> rets = entries[i]->retainers();
+ int j = 0;
+ for (; j < rets.length(); ++j) {
+ if (rets[j]->type() == HeapGraphEdge::kShortcut) continue;
+ HeapEntry* ret = rets[j]->From();
+ if (dominators->at(ret->ordered_index()) != NULL) {
+ new_idom = ret;
+ break;
+ }
+ }
+ for (++j; j < rets.length(); ++j) {
+ if (rets[j]->type() == HeapGraphEdge::kShortcut) continue;
+ HeapEntry* ret = rets[j]->From();
+ if (dominators->at(ret->ordered_index()) != NULL) {
+ new_idom = entries[Intersect(ret->ordered_index(),
+ new_idom->ordered_index(),
+ *dominators)];
+ }
+ }
+ if (new_idom != NULL && dominators->at(i) != new_idom) {
+ dominators->at(i) = new_idom;
+ changed = true;
+ }
+ }
+ }
+}
+
+
+void HeapSnapshot::SetEntriesDominators() {
+ // This array is used for maintaining reverse postorder of nodes.
+ ScopedVector<HeapEntry*> ordered_entries(entries_.length());
+ FillReversePostorderIndexes(&ordered_entries);
+ ScopedVector<HeapEntry*> dominators(ordered_entries.length());
+ BuildDominatorTree(ordered_entries, &dominators);
+ for (int i = 0; i < ordered_entries.length(); ++i) {
+ ASSERT(dominators[i] != NULL);
+ ordered_entries[i]->set_dominator(dominators[i]);
+ }
+ // For nodes unreachable from root, set dominator to itself.
+ for (int i = 0; i < entries_.length(); ++i) {
+ HeapEntry* entry = entries_[i];
+ if (entry->dominator() == NULL) entry->set_dominator(entry);
+ }
+}
+
+
+void HeapSnapshot::ApproximateRetainedSizes() {
+ SetEntriesDominators();
+ // As for the dominators tree we only know parent nodes, not
+ // children, to sum up total sizes we traverse the tree level by
+ // level upwards, starting from leaves.
+ for (int i = 0; i < entries_.length(); ++i) {
+ HeapEntry* entry = entries_[i];
+ entry->set_retained_size(entry->self_size());
+ entry->set_leaf();
+ }
+ while (true) {
+ bool onlyLeaves = true;
+ for (int i = 0; i < entries_.length(); ++i) {
+ HeapEntry *entry = entries_[i], *dominator = entry->dominator();
+ if (!entry->is_processed() && dominator != entry) {
+ dominator->set_non_leaf();
+ onlyLeaves = false;
+ }
+ }
+ if (onlyLeaves) break;
+
+ for (int i = 0; i < entries_.length(); ++i) {
+ HeapEntry *entry = entries_[i], *dominator = entry->dominator();
+ if (entry->is_leaf() && dominator != entry) {
+ dominator->add_retained_size(entry->retained_size());
+ }
+ }
+
+ // Mark all current leaves as processed, reset non-leaves back to leaves.
+ for (int i = 0; i < entries_.length(); ++i) {
+ HeapEntry* entry = entries_[i];
+ if (entry->is_leaf())
+ entry->set_processed();
+ else if (entry->is_non_leaf())
+ entry->set_leaf();
+ }
+ }
+}
+
+
HeapEntry* HeapSnapshot::GetNextEntryToInit() {
if (entries_.length() > 0) {
HeapEntry* last_entry = entries_.last();
@@ -1419,41 +1534,21 @@
}
-int HeapSnapshot::GetObjectSize(HeapObject* obj) {
- return obj->IsJSObject() ?
- CalculateNetworkSize(JSObject::cast(obj)) : obj->Size();
+HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) {
+ return collection_->CompareSnapshots(this, snapshot);
}
-int HeapSnapshot::CalculateNetworkSize(JSObject* obj) {
- int size = obj->Size();
- // If 'properties' and 'elements' are non-empty (thus, non-shared),
- // take their size into account.
- if (obj->properties() != Heap::empty_fixed_array()) {
- size += obj->properties()->Size();
+List<HeapGraphPath*>* HeapSnapshot::GetRetainingPaths(HeapEntry* entry) {
+ HashMap::Entry* p =
+ retaining_paths_.Lookup(entry, HeapEntry::Hash(entry), true);
+ if (p->value == NULL) {
+ p->value = entry->CalculateRetainingPaths();
}
- if (obj->elements() != Heap::empty_fixed_array()) {
- size += obj->elements()->Size();
- }
- // For functions, also account non-empty context and literals sizes.
- if (obj->IsJSFunction()) {
- JSFunction* f = JSFunction::cast(obj);
- if (f->unchecked_context()->IsContext()) {
- size += f->context()->Size();
- }
- if (f->literals()->length() != 0) {
- size += f->literals()->Size();
- }
- }
- return size;
+ return reinterpret_cast<List<HeapGraphPath*>*>(p->value);
}
-HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) {
- return collection_->CompareSnapshots(this, snapshot);
-}
-
-
template<class T>
static int SortByIds(const T* entry1_ptr,
const T* entry2_ptr) {
@@ -1475,9 +1570,14 @@
}
+const uint64_t HeapObjectsMap::kInternalRootObjectId = 0;
+const uint64_t HeapObjectsMap::kGcRootsObjectId = 1;
+// Increase kFirstAvailableObjectId if new 'special' objects appear.
+const uint64_t HeapObjectsMap::kFirstAvailableObjectId = 2;
+
HeapObjectsMap::HeapObjectsMap()
: initial_fill_mode_(true),
- next_id_(1),
+ next_id_(kFirstAvailableObjectId),
entries_map_(AddressesMatch),
entries_(new List<EntryInfo>()) { }
@@ -1628,26 +1728,15 @@
HeapEntriesMap::~HeapEntriesMap() {
for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) {
- if (!IsAlias(p->value)) delete reinterpret_cast<EntryInfo*>(p->value);
+ delete reinterpret_cast<EntryInfo*>(p->value);
}
}
-void HeapEntriesMap::Alias(HeapObject* from, HeapObject* to) {
- HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), true);
- HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false);
- if (from_cache_entry->value == NULL) {
- ASSERT(to_cache_entry != NULL);
- from_cache_entry->value = MakeAlias(to_cache_entry->value);
- }
-}
-
-
HeapEntry* HeapEntriesMap::Map(HeapObject* object) {
HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), false);
if (cache_entry != NULL) {
- EntryInfo* entry_info =
- reinterpret_cast<EntryInfo*>(Unalias(cache_entry->value));
+ EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value);
return entry_info->entry;
} else {
return NULL;
@@ -1671,9 +1760,9 @@
ASSERT(from_cache_entry != NULL);
ASSERT(to_cache_entry != NULL);
EntryInfo* from_entry_info =
- reinterpret_cast<EntryInfo*>(Unalias(from_cache_entry->value));
+ reinterpret_cast<EntryInfo*>(from_cache_entry->value);
EntryInfo* to_entry_info =
- reinterpret_cast<EntryInfo*>(Unalias(to_cache_entry->value));
+ reinterpret_cast<EntryInfo*>(to_cache_entry->value);
if (prev_children_count)
*prev_children_count = from_entry_info->children_count;
if (prev_retainers_count)
@@ -1685,6 +1774,36 @@
}
+HeapObjectsSet::HeapObjectsSet()
+ : entries_(HeapEntriesMap::HeapObjectsMatch) {
+}
+
+
+void HeapObjectsSet::Clear() {
+ entries_.Clear();
+}
+
+
+bool HeapObjectsSet::Contains(Object* obj) {
+ if (!obj->IsHeapObject()) return false;
+ HeapObject* object = HeapObject::cast(obj);
+ HashMap::Entry* cache_entry =
+ entries_.Lookup(object, HeapEntriesMap::Hash(object), false);
+ return cache_entry != NULL;
+}
+
+
+void HeapObjectsSet::Insert(Object* obj) {
+ if (!obj->IsHeapObject()) return;
+ HeapObject* object = HeapObject::cast(obj);
+ HashMap::Entry* cache_entry =
+ entries_.Lookup(object, HeapEntriesMap::Hash(object), true);
+ if (cache_entry->value == NULL) {
+ cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder;
+ }
+}
+
+
HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot)
: snapshot_(snapshot),
collection_(snapshot->collection()),
@@ -1699,7 +1818,8 @@
entries_->Pair(obj, HeapEntriesMap::kHeapEntryPlaceholder);
return HeapEntriesMap::kHeapEntryPlaceholder;
}
- void SetElementReference(HeapObject* parent_obj,
+ void SetIndexedReference(HeapGraphEdge::Type,
+ HeapObject* parent_obj,
HeapEntry*,
int,
Object* child_obj,
@@ -1714,10 +1834,18 @@
HeapEntry*) {
entries_->CountReference(parent_obj, HeapObject::cast(child_obj));
}
- void SetRootReference(Object* child_obj, HeapEntry*) {
+ void SetRootShortcutReference(Object* child_obj, HeapEntry*) {
entries_->CountReference(
HeapSnapshot::kInternalRootObject, HeapObject::cast(child_obj));
}
+ void SetRootGcRootsReference() {
+ entries_->CountReference(
+ HeapSnapshot::kInternalRootObject, HeapSnapshot::kGcRootsObject);
+ }
+ void SetStrongRootReference(Object* child_obj, HeapEntry*) {
+ entries_->CountReference(
+ HeapSnapshot::kGcRootsObject, HeapObject::cast(child_obj));
+ }
private:
HeapEntriesMap* entries_;
};
@@ -1733,16 +1861,19 @@
UNREACHABLE();
return NULL;
}
- void SetElementReference(HeapObject* parent_obj,
+ void SetIndexedReference(HeapGraphEdge::Type type,
+ HeapObject* parent_obj,
HeapEntry* parent_entry,
int index,
Object* child_obj,
HeapEntry* child_entry) {
int child_index, retainer_index;
- entries_->CountReference(parent_obj, HeapObject::cast(child_obj),
- &child_index, &retainer_index);
- parent_entry->SetElementReference(
- child_index, index, child_entry, retainer_index);
+ entries_->CountReference(parent_obj,
+ HeapObject::cast(child_obj),
+ &child_index,
+ &retainer_index);
+ parent_entry->SetIndexedReference(
+ type, child_index, index, child_entry, retainer_index);
}
void SetNamedReference(HeapGraphEdge::Type type,
HeapObject* parent_obj,
@@ -1759,14 +1890,44 @@
child_entry,
retainer_index);
}
- void SetRootReference(Object* child_obj, HeapEntry* child_entry) {
+ void SetRootGcRootsReference() {
int child_index, retainer_index;
- entries_->CountReference(
- HeapSnapshot::kInternalRootObject, HeapObject::cast(child_obj),
- &child_index, &retainer_index);
- snapshot_->root()->SetElementReference(
- child_index, child_index + 1, child_entry, retainer_index);
+ entries_->CountReference(HeapSnapshot::kInternalRootObject,
+ HeapSnapshot::kGcRootsObject,
+ &child_index,
+ &retainer_index);
+ snapshot_->root()->SetIndexedReference(HeapGraphEdge::kElement,
+ child_index,
+ child_index + 1,
+ snapshot_->gc_roots(),
+ retainer_index);
}
+ void SetRootShortcutReference(Object* child_obj,
+ HeapEntry* child_entry) {
+ int child_index, retainer_index;
+ entries_->CountReference(HeapSnapshot::kInternalRootObject,
+ HeapObject::cast(child_obj),
+ &child_index,
+ &retainer_index);
+ snapshot_->root()->SetNamedReference(HeapGraphEdge::kShortcut,
+ child_index,
+ collection_->GetName(child_index + 1),
+ child_entry,
+ retainer_index);
+ }
+ void SetStrongRootReference(Object* child_obj,
+ HeapEntry* child_entry) {
+ int child_index, retainer_index;
+ entries_->CountReference(HeapSnapshot::kGcRootsObject,
+ HeapObject::cast(child_obj),
+ &child_index,
+ &retainer_index);
+ snapshot_->gc_roots()->SetIndexedReference(HeapGraphEdge::kElement,
+ child_index,
+ child_index + 1,
+ child_entry,
+ retainer_index);
+ }
private:
HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_;
@@ -1788,6 +1949,19 @@
HeapSnapshot* snapshot_;
};
+class RootsReferencesExtractor : public ObjectVisitor {
+ public:
+ explicit RootsReferencesExtractor(HeapSnapshotGenerator* generator)
+ : generator_(generator) {
+ }
+ void VisitPointers(Object** start, Object** end) {
+ for (Object** p = start; p < end; p++) generator_->SetGcRootsReference(*p);
+ }
+ private:
+ HeapSnapshotGenerator* generator_;
+};
+
+
void HeapSnapshotGenerator::GenerateSnapshot() {
AssertNoAllocation no_alloc;
@@ -1795,12 +1969,14 @@
SnapshotCounter counter(&entries_);
filler_ = &counter;
filler_->AddEntry(HeapSnapshot::kInternalRootObject);
- HeapIterator iterator1;
- for (HeapObject* obj = iterator1.next();
- obj != NULL;
- obj = iterator1.next()) {
+ filler_->AddEntry(HeapSnapshot::kGcRootsObject);
+ HeapIterator iterator(HeapIterator::kPreciseFiltering);
+ for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
ExtractReferences(obj);
}
+ SetRootGcRootsReference();
+ RootsReferencesExtractor extractor(this);
+ Heap::IterateRoots(&extractor, VISIT_ONLY_STRONG);
// Allocate and fill entries in the snapshot, allocate references.
snapshot_->AllocateEntries(entries_.entries_count(),
@@ -1812,12 +1988,14 @@
// Pass 2. Fill references.
SnapshotFiller filler(snapshot_, &entries_);
filler_ = &filler;
- HeapIterator iterator2;
- for (HeapObject* obj = iterator2.next();
- obj != NULL;
- obj = iterator2.next()) {
+ iterator.reset();
+ for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
ExtractReferences(obj);
}
+ SetRootGcRootsReference();
+ Heap::IterateRoots(&extractor, VISIT_ONLY_STRONG);
+
+ snapshot_->ApproximateRetainedSizes();
}
@@ -1825,25 +2003,8 @@
if (!obj->IsHeapObject()) return NULL;
HeapObject* object = HeapObject::cast(obj);
HeapEntry* entry = entries_.Map(object);
-
// A new entry.
- if (entry == NULL) {
- if (obj->IsJSGlobalPropertyCell()) {
- Object* cell_target = JSGlobalPropertyCell::cast(obj)->value();
- entry = GetEntry(cell_target);
- // If GPC references an object that we have interest in (see
- // HeapSnapshot::AddEntry, WillAddEntry), add the object. We
- // don't store HeapEntries for GPCs. Instead, we make our hash
- // map to point to object's HeapEntry by GPCs address.
- if (entry != NULL) {
- entries_.Alias(object, HeapObject::cast(cell_target));
- }
- return entry;
- }
-
- if (snapshot_->WillAddEntry(object)) entry = filler_->AddEntry(object);
- }
-
+ if (entry == NULL) entry = filler_->AddEntry(object);
return entry;
}
@@ -1852,43 +2013,44 @@
public:
IndexedReferencesExtractor(HeapSnapshotGenerator* generator,
HeapObject* parent_obj,
- HeapEntry* parent_entry)
+ HeapEntry* parent_entry,
+ HeapObjectsSet* known_references = NULL)
: generator_(generator),
parent_obj_(parent_obj),
parent_(parent_entry),
+ known_references_(known_references),
next_index_(1) {
}
-
- void VisitPointer(Object** o) {
- generator_->SetElementReference(parent_obj_, parent_, next_index_++, *o);
- }
-
void VisitPointers(Object** start, Object** end) {
- for (Object** p = start; p < end; p++) VisitPointer(p);
+ for (Object** p = start; p < end; p++) {
+ if (!known_references_ || !known_references_->Contains(*p)) {
+ generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p);
+ }
+ }
}
-
private:
HeapSnapshotGenerator* generator_;
HeapObject* parent_obj_;
HeapEntry* parent_;
+ HeapObjectsSet* known_references_;
int next_index_;
};
void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) {
- // We need to reference JS global objects from snapshot's root.
- // We use JSGlobalProxy because this is what embedder (e.g. browser)
- // uses for the global object.
- if (obj->IsJSGlobalProxy()) {
- JSGlobalProxy* proxy = JSGlobalProxy::cast(obj);
- SetRootReference(proxy->map()->prototype());
- return;
- }
-
HeapEntry* entry = GetEntry(obj);
if (entry == NULL) return; // No interest in this object.
- if (obj->IsJSObject()) {
+ known_references_.Clear();
+ if (obj->IsJSGlobalProxy()) {
+ // We need to reference JS global objects from snapshot's root.
+ // We use JSGlobalProxy because this is what embedder (e.g. browser)
+ // uses for the global object.
+ JSGlobalProxy* proxy = JSGlobalProxy::cast(obj);
+ SetRootShortcutReference(proxy->map()->prototype());
+ IndexedReferencesExtractor refs_extractor(this, obj, entry);
+ obj->Iterate(&refs_extractor);
+ } else if (obj->IsJSObject()) {
JSObject* js_obj = JSObject::cast(obj);
ExtractClosureReferences(js_obj, entry);
ExtractPropertyReferences(js_obj, entry);
@@ -1903,18 +2065,18 @@
obj, entry, Heap::prototype_symbol(), js_fun->prototype());
}
}
+ IndexedReferencesExtractor refs_extractor(
+ this, obj, entry, &known_references_);
+ obj->Iterate(&refs_extractor);
} else if (obj->IsString()) {
if (obj->IsConsString()) {
ConsString* cs = ConsString::cast(obj);
- SetInternalReference(obj, entry, "1", cs->first());
- SetInternalReference(obj, entry, "2", cs->second());
+ SetInternalReference(obj, entry, 1, cs->first());
+ SetInternalReference(obj, entry, 2, cs->second());
}
- } else if (obj->IsCode() || obj->IsSharedFunctionInfo() || obj->IsScript()) {
+ } else {
IndexedReferencesExtractor refs_extractor(this, obj, entry);
obj->Iterate(&refs_extractor);
- } else if (obj->IsFixedArray()) {
- IndexedReferencesExtractor refs_extractor(this, obj, entry);
- obj->Iterate(&refs_extractor);
}
}
@@ -1967,8 +2129,17 @@
for (int i = 0; i < length; ++i) {
Object* k = dictionary->KeyAt(i);
if (dictionary->IsKey(k)) {
+ Object* target = dictionary->ValueAt(i);
SetPropertyReference(
- js_obj, entry, String::cast(k), dictionary->ValueAt(i));
+ js_obj, entry, String::cast(k), target);
+ // We assume that global objects can only have slow properties.
+ if (target->IsJSGlobalPropertyCell()) {
+ SetPropertyShortcutReference(js_obj,
+ entry,
+ String::cast(k),
+ JSGlobalPropertyCell::cast(
+ target)->value());
+ }
}
}
}
@@ -2024,6 +2195,7 @@
collection_->GetName(reference_name),
child_obj,
child_entry);
+ known_references_.Insert(child_obj);
}
}
@@ -2034,8 +2206,13 @@
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
- filler_->SetElementReference(
- parent_obj, parent_entry, index, child_obj, child_entry);
+ filler_->SetIndexedReference(HeapGraphEdge::kElement,
+ parent_obj,
+ parent_entry,
+ index,
+ child_obj,
+ child_entry);
+ known_references_.Insert(child_obj);
}
}
@@ -2052,6 +2229,7 @@
reference_name,
child_obj,
child_entry);
+ known_references_.Insert(child_obj);
}
}
@@ -2068,10 +2246,27 @@
collection_->GetName(index),
child_obj,
child_entry);
+ known_references_.Insert(child_obj);
}
}
+void HeapSnapshotGenerator::SetHiddenReference(HeapObject* parent_obj,
+ HeapEntry* parent_entry,
+ int index,
+ Object* child_obj) {
+ HeapEntry* child_entry = GetEntry(child_obj);
+ if (child_entry != NULL) {
+ filler_->SetIndexedReference(HeapGraphEdge::kHidden,
+ parent_obj,
+ parent_entry,
+ index,
+ child_obj,
+ child_entry);
+ }
+}
+
+
void HeapSnapshotGenerator::SetPropertyReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
String* reference_name,
@@ -2086,26 +2281,57 @@
collection_->GetName(reference_name),
child_obj,
child_entry);
+ known_references_.Insert(child_obj);
}
}
-void HeapSnapshotGenerator::SetRootReference(Object* child_obj) {
+void HeapSnapshotGenerator::SetPropertyShortcutReference(
+ HeapObject* parent_obj,
+ HeapEntry* parent_entry,
+ String* reference_name,
+ Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
+ if (child_entry != NULL) {
+ filler_->SetNamedReference(HeapGraphEdge::kShortcut,
+ parent_obj,
+ parent_entry,
+ collection_->GetName(reference_name),
+ child_obj,
+ child_entry);
+ }
+}
+
+
+void HeapSnapshotGenerator::SetRootGcRootsReference() {
+ filler_->SetRootGcRootsReference();
+}
+
+
+void HeapSnapshotGenerator::SetRootShortcutReference(Object* child_obj) {
+ HeapEntry* child_entry = GetEntry(child_obj);
ASSERT(child_entry != NULL);
- filler_->SetRootReference(child_obj, child_entry);
+ filler_->SetRootShortcutReference(child_obj, child_entry);
}
+void HeapSnapshotGenerator::SetGcRootsReference(Object* child_obj) {
+ HeapEntry* child_entry = GetEntry(child_obj);
+ if (child_entry != NULL) {
+ filler_->SetStrongRootReference(child_obj, child_entry);
+ }
+}
+
+
void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) {
raw_additions_root_ =
NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0));
additions_root()->Init(
- snapshot2_, HeapEntry::kInternal, "", 0, 0, additions_count, 0);
+ snapshot2_, HeapEntry::kHidden, "", 0, 0, additions_count, 0);
raw_deletions_root_ =
NewArray<char>(HeapEntry::EntriesSize(1, deletions_count, 0));
deletions_root()->Init(
- snapshot1_, HeapEntry::kInternal, "", 0, 0, deletions_count, 0);
+ snapshot1_, HeapEntry::kHidden, "", 0, 0, deletions_count, 0);
}
@@ -2324,7 +2550,8 @@
writer_->AddCharacter(',');
writer_->AddNumber(edge->type());
writer_->AddCharacter(',');
- if (edge->type() == HeapGraphEdge::kElement) {
+ if (edge->type() == HeapGraphEdge::kElement
+ || edge->type() == HeapGraphEdge::kHidden) {
writer_->AddNumber(edge->index());
} else {
writer_->AddNumber(GetStringId(edge->name()));
@@ -2344,6 +2571,10 @@
writer_->AddNumber(entry->id());
writer_->AddCharacter(',');
writer_->AddNumber(entry->self_size());
+ writer_->AddCharacter(',');
+ writer_->AddNumber(entry->RetainedSize(false));
+ writer_->AddCharacter(',');
+ writer_->AddNumber(GetNodeId(entry->dominator()));
Vector<HeapGraphEdge> children = entry->children();
writer_->AddCharacter(',');
writer_->AddNumber(children.length());
@@ -2355,23 +2586,25 @@
void HeapSnapshotJSONSerializer::SerializeNodes() {
- // The first (zero) item of nodes array is a JSON-ified object
- // describing node serialization layout.
- // We use a set of macros to improve readability.
+ // The first (zero) item of nodes array is an object describing node
+ // serialization layout. We use a set of macros to improve
+ // readability.
#define JSON_A(s) "["s"]"
#define JSON_O(s) "{"s"}"
-#define JSON_S(s) "\\\""s"\\\""
- writer_->AddString("\"" JSON_O(
+#define JSON_S(s) "\""s"\""
+ writer_->AddString(JSON_O(
JSON_S("fields") ":" JSON_A(
JSON_S("type")
"," JSON_S("name")
"," JSON_S("id")
"," JSON_S("self_size")
+ "," JSON_S("retained_size")
+ "," JSON_S("dominator")
"," JSON_S("children_count")
"," JSON_S("children"))
"," JSON_S("types") ":" JSON_A(
JSON_A(
- JSON_S("internal")
+ JSON_S("hidden")
"," JSON_S("array")
"," JSON_S("string")
"," JSON_S("object")
@@ -2383,6 +2616,8 @@
"," JSON_S("number")
"," JSON_S("number")
"," JSON_S("number")
+ "," JSON_S("number")
+ "," JSON_S("number")
"," JSON_O(
JSON_S("fields") ":" JSON_A(
JSON_S("type")
@@ -2393,14 +2628,17 @@
JSON_S("context")
"," JSON_S("element")
"," JSON_S("property")
- "," JSON_S("internal"))
+ "," JSON_S("internal")
+ "," JSON_S("hidden")
+ "," JSON_S("shortcut"))
"," JSON_S("string_or_number")
- "," JSON_S("node"))))) "\"");
+ "," JSON_S("node"))))));
#undef JSON_S
#undef JSON_O
#undef JSON_A
- const int node_fields_count = 5; // type,name,id,self_size,children_count.
+ const int node_fields_count = 7;
+ // type,name,id,self_size,retained_size,dominator,children_count.
const int edge_fields_count = 3; // type,name|index,to_node.
List<HashMap::Entry*> sorted_nodes;
SortHashMap(&nodes_, &sorted_nodes);
« no previous file with comments | « src/profile-generator.h ('k') | src/profile-generator-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698