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

Unified Diff: src/profile-generator.cc

Issue 3060008: Heap profiler: reduce heap snapshots size. (Closed)
Patch Set: Comments addressed Created 10 years, 4 months 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
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 7054b125950863776f41a5555d8aeaf807bb5a83..01c4e4fe8709a2eb4e1030bba3d828c7d9c4e7d6 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -798,83 +798,102 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
}
-HeapGraphEdge::HeapGraphEdge(Type type,
- const char* name,
- HeapEntry* from,
- HeapEntry* to)
- : type_(type), name_(name), from_(from), to_(to) {
- ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY || type_ == INTERNAL);
+void HeapGraphEdge::Init(
+ int child_index, Type type, const char* name, HeapEntry* to) {
+ ASSERT(type == kContextVariable || type == kProperty || type == kInternal);
+ child_index_ = child_index;
+ type_ = type;
+ name_ = name;
+ to_ = to;
}
-HeapGraphEdge::HeapGraphEdge(int index,
- HeapEntry* from,
- HeapEntry* to)
- : type_(ELEMENT), index_(index), from_(from), to_(to) {
+void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) {
+ child_index_ = child_index;
+ type_ = kElement;
+ index_ = index;
+ to_ = to;
}
-static void DeleteHeapGraphEdge(HeapGraphEdge** edge_ptr) {
- delete *edge_ptr;
+HeapEntry* HeapGraphEdge::From() {
+ return reinterpret_cast<HeapEntry*>(this - child_index_) - 1;
}
-static void DeleteHeapGraphPath(HeapGraphPath** path_ptr) {
- delete *path_ptr;
+void HeapEntry::Init(HeapSnapshot* snapshot,
+ int children_count,
+ int retainers_count) {
+ Init(snapshot, kInternal, "", 0, 0, children_count, retainers_count);
}
-HeapEntry::~HeapEntry() {
- children_.Iterate(DeleteHeapGraphEdge);
- retaining_paths_.Iterate(DeleteHeapGraphPath);
+void HeapEntry::Init(HeapSnapshot* snapshot,
+ Type type,
+ const char* name,
+ uint64_t id,
+ int self_size,
+ int children_count,
+ int retainers_count) {
+ snapshot_ = snapshot;
+ type_ = type;
+ painted_ = kUnpainted;
+ calculated_data_index_ = kNoCalculatedData;
+ name_ = name;
+ id_ = id;
+ self_size_ = self_size;
+ children_count_ = children_count;
+ retainers_count_ = retainers_count;
}
-void HeapEntry::AddEdge(HeapGraphEdge* edge) {
- children_.Add(edge);
- edge->to()->retainers_.Add(edge);
+void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
+ int child_index,
+ const char* name,
+ HeapEntry* entry,
+ int retainer_index) {
+ children_arr()[child_index].Init(child_index, type, name, entry);
+ entry->retainers_arr()[retainer_index] = children_arr() + child_index;
}
-void HeapEntry::SetClosureReference(const char* name, HeapEntry* entry) {
- AddEdge(
- new HeapGraphEdge(HeapGraphEdge::CONTEXT_VARIABLE, name, this, entry));
+void HeapEntry::SetElementReference(
+ int child_index, int index, HeapEntry* entry, int retainer_index) {
+ children_arr()[child_index].Init(child_index, index, entry);
+ entry->retainers_arr()[retainer_index] = children_arr() + child_index;
}
-void HeapEntry::SetElementReference(int index, HeapEntry* entry) {
- AddEdge(new HeapGraphEdge(index, this, entry));
+void HeapEntry::SetUnidirElementReference(
+ int child_index, int index, HeapEntry* entry) {
+ children_arr()[child_index].Init(child_index, index, entry);
}
-void HeapEntry::SetInternalReference(const char* name, HeapEntry* entry) {
- AddEdge(new HeapGraphEdge(HeapGraphEdge::INTERNAL, name, this, entry));
-}
-
-
-void HeapEntry::SetPropertyReference(const char* name, HeapEntry* entry) {
- AddEdge(new HeapGraphEdge(HeapGraphEdge::PROPERTY, name, this, entry));
-}
-
-
-void HeapEntry::SetAutoIndexReference(HeapEntry* entry) {
- SetElementReference(next_auto_index_++, entry);
-}
-
-
-void HeapEntry::SetUnidirAutoIndexReference(HeapEntry* entry) {
- children_.Add(new HeapGraphEdge(next_auto_index_++, this, entry));
+int HeapEntry::ReachableSize() {
+ if (calculated_data_index_ == kNoCalculatedData) {
+ calculated_data_index_ = snapshot_->AddCalculatedData();
+ }
+ return snapshot_->GetCalculatedData(
+ calculated_data_index_).ReachableSize(this);
}
-int HeapEntry::TotalSize() {
- return total_size_ != kUnknownSize ? total_size_ : CalculateTotalSize();
+int HeapEntry::RetainedSize() {
+ if (calculated_data_index_ == kNoCalculatedData) {
+ calculated_data_index_ = snapshot_->AddCalculatedData();
+ }
+ return snapshot_->GetCalculatedData(
+ calculated_data_index_).RetainedSize(this);
}
-int HeapEntry::NonSharedTotalSize() {
- return non_shared_total_size_ != kUnknownSize ?
- non_shared_total_size_ : CalculateNonSharedTotalSize();
+List<HeapGraphPath*>* HeapEntry::GetRetainingPaths() {
+ if (calculated_data_index_ == kNoCalculatedData) {
+ calculated_data_index_ = snapshot_->AddCalculatedData();
+ }
+ return snapshot_->GetCalculatedData(
+ calculated_data_index_).GetRetainingPaths(this);
}
@@ -882,16 +901,16 @@ template<class Visitor>
void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) {
List<HeapEntry*> list(10);
list.Add(this);
- this->PaintReachable();
+ this->paint_reachable();
visitor->Apply(this);
while (!list.is_empty()) {
HeapEntry* entry = list.RemoveLast();
- const int children_count = entry->children_.length();
- for (int i = 0; i < children_count; ++i) {
- HeapEntry* child = entry->children_[i]->to();
+ Vector<HeapGraphEdge> children = entry->children();
+ for (int i = 0; i < children.length(); ++i) {
+ HeapEntry* child = children[i].to();
if (!child->painted_reachable()) {
list.Add(child);
- child->PaintReachable();
+ child->paint_reachable();
visitor->Apply(child);
}
}
@@ -910,78 +929,158 @@ void HeapEntry::PaintAllReachable() {
}
-class TotalSizeCalculator {
- public:
- TotalSizeCalculator()
- : total_size_(0) {
+void HeapEntry::Print(int max_depth, int indent) {
+ OS::Print("%6d %6d %6d [%ld] ",
+ self_size(), ReachableSize(), RetainedSize(), id_);
+ if (type() != kString) {
+ OS::Print("%s %.40s\n", TypeAsString(), name_);
+ } else {
+ OS::Print("\"");
+ const char* c = name_;
+ while (*c && (c - name_) <= 40) {
+ if (*c != '\n')
+ OS::Print("%c", *c);
+ else
+ OS::Print("\\n");
+ ++c;
+ }
+ OS::Print("\"\n");
}
+ if (--max_depth == 0) return;
+ Vector<HeapGraphEdge> ch = children();
+ for (int i = 0; i < ch.length(); ++i) {
+ HeapGraphEdge& edge = ch[i];
+ switch (edge.type()) {
+ case HeapGraphEdge::kContextVariable:
+ OS::Print(" %*c #%s: ", indent, ' ', edge.name());
+ break;
+ case HeapGraphEdge::kElement:
+ OS::Print(" %*c %d: ", indent, ' ', edge.index());
+ break;
+ case HeapGraphEdge::kInternal:
+ OS::Print(" %*c $%s: ", indent, ' ', edge.name());
+ break;
+ case HeapGraphEdge::kProperty:
+ OS::Print(" %*c %s: ", indent, ' ', edge.name());
+ break;
+ default:
+ OS::Print("!!! unknown edge type: %d ", edge.type());
+ }
+ edge.to()->Print(max_depth, indent + 2);
+ }
+}
- int total_size() const { return total_size_; }
- void Apply(HeapEntry* entry) {
- total_size_ += entry->self_size();
+const char* HeapEntry::TypeAsString() {
+ switch (type()) {
+ case kInternal: return "/internal/";
+ case kObject: return "/object/";
+ case kClosure: return "/closure/";
+ case kString: return "/string/";
+ case kCode: return "/code/";
+ case kArray: return "/array/";
+ default: return "???";
}
+}
- private:
- int total_size_;
-};
-int HeapEntry::CalculateTotalSize() {
- snapshot_->ClearPaint();
- TotalSizeCalculator calc;
- ApplyAndPaintAllReachable(&calc);
- total_size_ = calc.total_size();
- return total_size_;
+int HeapEntry::EntriesSize(int entries_count,
+ int children_count,
+ int retainers_count) {
+ return sizeof(HeapEntry) * entries_count // NOLINT
+ + sizeof(HeapGraphEdge) * children_count // NOLINT
+ + sizeof(HeapGraphEdge*) * retainers_count; // NOLINT
}
-class NonSharedSizeCalculator {
+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:
- NonSharedSizeCalculator()
- : non_shared_total_size_(0) {
+ ReachableSizeCalculator()
+ : reachable_size_(0) {
}
- int non_shared_total_size() const { return non_shared_total_size_; }
+ int reachable_size() const { return reachable_size_; }
void Apply(HeapEntry* entry) {
- if (entry->painted_reachable()) {
- non_shared_total_size_ += entry->self_size();
+ reachable_size_ += entry->self_size();
+ }
+
+ private:
+ int reachable_size_;
+};
+
+class RetainedSizeCalculator {
+ public:
+ RetainedSizeCalculator()
+ : retained_size_(0) {
+ }
+
+ int reained_size() const { return retained_size_; }
+
+ void Apply(HeapEntry** entry_ptr) {
+ if ((*entry_ptr)->painted_reachable()) {
+ retained_size_ += (*entry_ptr)->self_size();
}
}
private:
- int non_shared_total_size_;
+ int retained_size_;
};
-int HeapEntry::CalculateNonSharedTotalSize() {
- // To calculate non-shared total size, first we paint all reachable
- // nodes in one color, then we paint all nodes reachable from other
- // nodes with a different color. Then we consider only nodes painted
- // with the first color for calculating the total size.
- snapshot_->ClearPaint();
- PaintAllReachable();
+void HeapEntryCalculatedData::CalculateSizes(HeapEntry* entry) {
+ // 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();
List<HeapEntry*> list(10);
- if (this != snapshot_->root()) {
- list.Add(snapshot_->root());
- snapshot_->root()->PaintReachableFromOthers();
+ HeapEntry* root = entry->snapshot()->root();
+ if (entry != root) {
+ list.Add(root);
+ root->paint_reachable_from_others();
}
while (!list.is_empty()) {
- HeapEntry* entry = list.RemoveLast();
- const int children_count = entry->children_.length();
- for (int i = 0; i < children_count; ++i) {
- HeapEntry* child = entry->children_[i]->to();
- if (child != this && child->not_painted_reachable_from_others()) {
+ HeapEntry* curr = list.RemoveLast();
+ Vector<HeapGraphEdge> children = curr->children();
+ for (int i = 0; i < children.length(); ++i) {
+ HeapEntry* child = children[i].to();
+ if (child != entry && child->not_painted_reachable_from_others()) {
list.Add(child);
- child->PaintReachableFromOthers();
+ child->paint_reachable_from_others();
}
}
}
- NonSharedSizeCalculator calculator;
- snapshot_->IterateEntries(&calculator);
- non_shared_total_size_ = calculator.non_shared_total_size();
- return non_shared_total_size_;
+ RetainedSizeCalculator ret_size_calc;
+ entry->snapshot()->IterateEntries(&ret_size_calc);
+ retained_size_ = ret_size_calc.reained_size();
}
@@ -1019,124 +1118,33 @@ class CachedHeapGraphPath {
};
-const List<HeapGraphPath*>* HeapEntry::GetRetainingPaths() {
- if (retaining_paths_.length() == 0 && retainers_.length() != 0) {
+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(this, &path);
+ FindRetainingPaths(entry, &path);
}
- return &retaining_paths_;
+ return retaining_paths_;
}
-void HeapEntry::FindRetainingPaths(HeapEntry* node,
- CachedHeapGraphPath* prev_path) {
- for (int i = 0; i < node->retainers_.length(); ++i) {
- HeapGraphEdge* ret_edge = node->retainers_[i];
- if (prev_path->ContainsNode(ret_edge->from())) continue;
- if (ret_edge->from() != snapshot_->root()) {
+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];
+ if (prev_path->ContainsNode(ret_edge->From())) continue;
+ if (ret_edge->From() != entry->snapshot()->root()) {
CachedHeapGraphPath path(*prev_path);
path.Add(ret_edge);
- FindRetainingPaths(ret_edge->from(), &path);
+ FindRetainingPaths(ret_edge->From(), &path);
} else {
HeapGraphPath* ret_path = new HeapGraphPath(*prev_path->path());
ret_path->Set(0, ret_edge);
- retaining_paths_.Add(ret_path);
- }
- }
-}
-
-
-static void RemoveEdge(List<HeapGraphEdge*>* list, HeapGraphEdge* edge) {
- for (int i = 0; i < list->length(); ) {
- if (list->at(i) == edge) {
- list->Remove(i);
- return;
- } else {
- ++i;
- }
- }
- UNREACHABLE();
-}
-
-
-void HeapEntry::RemoveChild(HeapGraphEdge* edge) {
- RemoveEdge(&children_, edge);
- delete edge;
-}
-
-
-void HeapEntry::RemoveRetainer(HeapGraphEdge* edge) {
- RemoveEdge(&retainers_, edge);
-}
-
-
-void HeapEntry::CutEdges() {
- for (int i = 0; i < children_.length(); ++i) {
- HeapGraphEdge* edge = children_[i];
- edge->to()->RemoveRetainer(edge);
- }
- children_.Iterate(DeleteHeapGraphEdge);
- children_.Clear();
-
- for (int i = 0; i < retainers_.length(); ++i) {
- HeapGraphEdge* edge = retainers_[i];
- edge->from()->RemoveChild(edge);
- }
- retainers_.Clear();
-}
-
-
-void HeapEntry::Print(int max_depth, int indent) {
- OS::Print("%6d %6d %6d [%ld] ",
- self_size_, TotalSize(), NonSharedTotalSize(), id_);
- if (type_ != STRING) {
- OS::Print("%s %.40s\n", TypeAsString(), name_);
- } else {
- OS::Print("\"");
- const char* c = name_;
- while (*c && (c - name_) <= 40) {
- if (*c != '\n')
- OS::Print("%c", *c);
- else
- OS::Print("\\n");
- ++c;
+ retaining_paths_->Add(ret_path);
}
- OS::Print("\"\n");
- }
- if (--max_depth == 0) return;
- const int children_count = children_.length();
- for (int i = 0; i < children_count; ++i) {
- HeapGraphEdge* edge = children_[i];
- switch (edge->type()) {
- case HeapGraphEdge::CONTEXT_VARIABLE:
- OS::Print(" %*c #%s: ", indent, ' ', edge->name());
- break;
- case HeapGraphEdge::ELEMENT:
- OS::Print(" %*c %d: ", indent, ' ', edge->index());
- break;
- case HeapGraphEdge::INTERNAL:
- OS::Print(" %*c $%s: ", indent, ' ', edge->name());
- break;
- case HeapGraphEdge::PROPERTY:
- OS::Print(" %*c %s: ", indent, ' ', edge->name());
- break;
- default:
- OS::Print("!!! unknown edge type: %d ", edge->type());
- }
- edge->to()->Print(max_depth, indent + 2);
- }
-}
-
-
-const char* HeapEntry::TypeAsString() {
- switch (type_) {
- case INTERNAL: return "/internal/";
- case OBJECT: return "/object/";
- case CLOSURE: return "/closure/";
- case STRING: return "/string/";
- case CODE: return "/code/";
- case ARRAY: return "/array/";
- default: return "???";
}
}
@@ -1151,21 +1159,21 @@ HeapGraphPath::HeapGraphPath(const List<HeapGraphEdge*>& path)
void HeapGraphPath::Print() {
- path_[0]->from()->Print(1, 0);
+ path_[0]->From()->Print(1, 0);
for (int i = 0; i < path_.length(); ++i) {
OS::Print(" -> ");
HeapGraphEdge* edge = path_[i];
switch (edge->type()) {
- case HeapGraphEdge::CONTEXT_VARIABLE:
+ case HeapGraphEdge::kContextVariable:
OS::Print("[#%s] ", edge->name());
break;
- case HeapGraphEdge::ELEMENT:
+ case HeapGraphEdge::kElement:
OS::Print("[%d] ", edge->index());
break;
- case HeapGraphEdge::INTERNAL:
+ case HeapGraphEdge::kInternal:
OS::Print("[$%s] ", edge->name());
break;
- case HeapGraphEdge::PROPERTY:
+ case HeapGraphEdge::kProperty:
OS::Print("[%s] ", edge->name());
break;
default:
@@ -1177,76 +1185,8 @@ void HeapGraphPath::Print() {
}
-class IndexedReferencesExtractor : public ObjectVisitor {
- public:
- IndexedReferencesExtractor(HeapSnapshot* snapshot, HeapEntry* parent)
- : snapshot_(snapshot),
- parent_(parent) {
- }
-
- void VisitPointer(Object** o) {
- if (!(*o)->IsHeapObject()) return;
- HeapEntry* entry = snapshot_->GetEntry(HeapObject::cast(*o));
- if (entry != NULL) {
- parent_->SetAutoIndexReference(entry);
- }
- }
-
- void VisitPointers(Object** start, Object** end) {
- for (Object** p = start; p < end; p++) VisitPointer(p);
- }
-
- private:
- HeapSnapshot* snapshot_;
- HeapEntry* parent_;
-};
-
-
-HeapEntriesMap::HeapEntriesMap()
- : entries_(HeapObjectsMatch) {
-}
-
-
-HeapEntriesMap::~HeapEntriesMap() {
- for (HashMap::Entry* p = entries_.Start();
- p != NULL;
- p = entries_.Next(p)) {
- if (!IsAlias(p->value)) delete reinterpret_cast<HeapEntry*>(p->value);
- }
-}
-
-
-void HeapEntriesMap::Alias(HeapObject* object, HeapEntry* entry) {
- HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true);
- if (cache_entry->value == NULL)
- cache_entry->value = reinterpret_cast<void*>(
- reinterpret_cast<intptr_t>(entry) | kAliasTag);
-}
-
-
-void HeapEntriesMap::Apply(void (HeapEntry::*Func)(void)) {
- for (HashMap::Entry* p = entries_.Start();
- p != NULL;
- p = entries_.Next(p)) {
- if (!IsAlias(p->value)) (reinterpret_cast<HeapEntry*>(p->value)->*Func)();
- }
-}
-
-
-HeapEntry* HeapEntriesMap::Map(HeapObject* object) {
- HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), false);
- return cache_entry != NULL ?
- reinterpret_cast<HeapEntry*>(
- reinterpret_cast<intptr_t>(cache_entry->value) & (~kAliasTag)) : NULL;
-}
-
-
-void HeapEntriesMap::Pair(HeapObject* object, HeapEntry* entry) {
- HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true);
- ASSERT(cache_entry->value == NULL);
- cache_entry->value = entry;
-}
-
+HeapObject *const HeapSnapshot::kInternalRootObject =
+ reinterpret_cast<HeapObject*>(1);
HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
const char* title,
@@ -1254,176 +1194,151 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
: collection_(collection),
title_(title),
uid_(uid),
- root_(this),
- sorted_entries_(NULL) {
+ root_entry_index_(-1),
+ raw_entries_(NULL),
+ entries_sorted_(false) {
}
-HeapSnapshot::~HeapSnapshot() {
- delete sorted_entries_;
+static void DisposeCalculatedData(HeapEntryCalculatedData* cdata) {
+ cdata->Dispose();
}
-
-void HeapSnapshot::ClearPaint() {
- root_.ClearPaint();
- entries_.Apply(&HeapEntry::ClearPaint);
+HeapSnapshot::~HeapSnapshot() {
+ DeleteArray(raw_entries_);
+ calculated_data_.Iterate(DisposeCalculatedData);
}
-HeapEntry* HeapSnapshot::GetEntry(Object* obj) {
- if (!obj->IsHeapObject()) return NULL;
- HeapObject* object = HeapObject::cast(obj);
+void HeapSnapshot::AllocateEntries(int entries_count,
+ int children_count,
+ int retainers_count) {
+ ASSERT(raw_entries_ == NULL);
+ raw_entries_ = NewArray<char>(
+ HeapEntry::EntriesSize(entries_count, children_count, retainers_count));
+}
- {
- HeapEntry* existing = FindEntry(object);
- if (existing != NULL) return existing;
- }
- // Add new entry.
- if (object->IsJSFunction()) {
+HeapEntry* HeapSnapshot::AddEntry(HeapObject* object,
+ int children_count,
+ int retainers_count) {
+ if (object == kInternalRootObject) {
+ ASSERT(root_entry_index_ == -1);
+ root_entry_index_ = entries_.length();
+ HeapEntry* entry = GetNextEntryToInit();
+ entry->Init(this, children_count, retainers_count);
+ return entry;
+ } else if (object->IsJSFunction()) {
JSFunction* func = JSFunction::cast(object);
SharedFunctionInfo* shared = func->shared();
String* name = String::cast(shared->name())->length() > 0 ?
String::cast(shared->name()) : shared->inferred_name();
- return AddEntry(object, HeapEntry::CLOSURE, collection_->GetName(name));
+ return AddEntry(object,
+ HeapEntry::kClosure,
+ collection_->GetName(name),
+ children_count,
+ retainers_count);
} else if (object->IsJSObject()) {
return AddEntry(object,
- HeapEntry::OBJECT,
+ HeapEntry::kObject,
collection_->GetName(
- JSObject::cast(object)->constructor_name()));
- } else if (object->IsJSGlobalPropertyCell()) {
- HeapEntry* value = GetEntry(JSGlobalPropertyCell::cast(object)->value());
- // If GPC references an object that we have interest in, 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 (value != NULL) AddEntryAlias(object, value);
- return value;
+ JSObject::cast(object)->constructor_name()),
+ children_count,
+ retainers_count);
} else if (object->IsString()) {
return AddEntry(object,
- HeapEntry::STRING,
- collection_->GetName(String::cast(object)));
+ HeapEntry::kString,
+ collection_->GetName(String::cast(object)),
+ children_count,
+ retainers_count);
} else if (object->IsCode()) {
- return AddEntry(object, HeapEntry::CODE);
+ return AddEntry(object,
+ HeapEntry::kCode,
+ "",
+ children_count,
+ retainers_count);
} else if (object->IsSharedFunctionInfo()) {
SharedFunctionInfo* shared = SharedFunctionInfo::cast(object);
String* name = String::cast(shared->name())->length() > 0 ?
String::cast(shared->name()) : shared->inferred_name();
- return AddEntry(object, HeapEntry::CODE, collection_->GetName(name));
+ return AddEntry(object,
+ HeapEntry::kCode,
+ collection_->GetName(name),
+ children_count,
+ retainers_count);
} else if (object->IsScript()) {
Script* script = Script::cast(object);
return AddEntry(object,
- HeapEntry::CODE,
+ HeapEntry::kCode,
script->name()->IsString() ?
- collection_->GetName(String::cast(script->name())) : "");
+ collection_->GetName(String::cast(script->name())) : "",
+ children_count,
+ retainers_count);
} else if (object->IsFixedArray()) {
- return AddEntry(object, HeapEntry::ARRAY);
+ return AddEntry(object,
+ HeapEntry::kArray,
+ "",
+ children_count,
+ retainers_count);
}
// No interest in this object.
return NULL;
}
-void HeapSnapshot::SetClosureReference(HeapEntry* parent,
- String* reference_name,
- Object* child) {
- HeapEntry* child_entry = GetEntry(child);
- if (child_entry != NULL) {
- parent->SetClosureReference(
- collection_->GetName(reference_name), child_entry);
- }
+bool HeapSnapshot::WillAddEntry(HeapObject* object) {
+ return object == kInternalRootObject
+ || object->IsJSFunction()
+ || object->IsJSObject()
+ || object->IsString()
+ || object->IsCode()
+ || object->IsSharedFunctionInfo()
+ || object->IsScript()
+ || object->IsFixedArray();
}
-void HeapSnapshot::SetElementReference(HeapEntry* parent,
- int index,
- Object* child) {
- HeapEntry* child_entry = GetEntry(child);
- if (child_entry != NULL) {
- parent->SetElementReference(index, child_entry);
- }
+static void HeapEntryClearPaint(HeapEntry** entry_ptr) {
+ (*entry_ptr)->clear_paint();
}
-
-void HeapSnapshot::SetInternalReference(HeapEntry* parent,
- const char* reference_name,
- Object* child) {
- HeapEntry* child_entry = GetEntry(child);
- if (child_entry != NULL) {
- parent->SetInternalReference(reference_name, child_entry);
- }
+void HeapSnapshot::ClearPaint() {
+ entries_.Iterate(HeapEntryClearPaint);
}
-void HeapSnapshot::SetPropertyReference(HeapEntry* parent,
- String* reference_name,
- Object* child) {
- HeapEntry* child_entry = GetEntry(child);
- if (child_entry != NULL) {
- parent->SetPropertyReference(
- collection_->GetName(reference_name), child_entry);
- }
+int HeapSnapshot::AddCalculatedData() {
+ calculated_data_.Add(HeapEntryCalculatedData());
+ return calculated_data_.length() - 1;
}
HeapEntry* HeapSnapshot::AddEntry(HeapObject* object,
HeapEntry::Type type,
- const char* name) {
- HeapEntry* entry = new HeapEntry(this,
- type,
- name,
- collection_->GetObjectId(object->address()),
- GetObjectSize(object),
- GetObjectSecurityToken(object));
- entries_.Pair(object, entry);
-
- // Detect, if this is a JS global object of the current context, and
- // add it to snapshot's roots. There can be several JS global objects
- // in a context.
- if (object->IsJSGlobalProxy()) {
- int global_security_token = GetGlobalSecurityToken();
- int object_security_token =
- collection_->token_enumerator()->GetTokenId(
- Context::cast(
- JSGlobalProxy::cast(object)->context())->security_token());
- if (object_security_token == TokenEnumerator::kNoSecurityToken
- || object_security_token == global_security_token) {
- HeapEntry* global_object_entry =
- GetEntry(HeapObject::cast(object->map()->prototype()));
- ASSERT(global_object_entry != NULL);
- root_.SetAutoIndexReference(global_object_entry);
- }
- }
-
+ const char* name,
+ int children_count,
+ int retainers_count) {
+ HeapEntry* entry = GetNextEntryToInit();
+ entry->Init(this,
+ type,
+ name,
+ collection_->GetObjectId(object->address()),
+ GetObjectSize(object),
+ children_count,
+ retainers_count);
return entry;
}
-class EdgesCutter {
- public:
- explicit EdgesCutter(int global_security_token)
- : global_security_token_(global_security_token) {
- }
-
- void Apply(HeapEntry* entry) {
- if (entry->security_token_id() != TokenEnumerator::kNoSecurityToken
- && entry->security_token_id() != global_security_token_) {
- entry->CutEdges();
- }
+HeapEntry* HeapSnapshot::GetNextEntryToInit() {
+ if (entries_.length() > 0) {
+ HeapEntry* last_entry = entries_.last();
+ entries_.Add(reinterpret_cast<HeapEntry*>(
+ reinterpret_cast<char*>(last_entry) + last_entry->EntrySize()));
+ } else {
+ entries_.Add(reinterpret_cast<HeapEntry*>(raw_entries_));
}
-
- private:
- const int global_security_token_;
-};
-
-void HeapSnapshot::CutObjectsFromForeignSecurityContexts() {
- EdgesCutter cutter(GetGlobalSecurityToken());
- entries_.Apply(&cutter);
-}
-
-
-int HeapSnapshot::GetGlobalSecurityToken() {
- return collection_->token_enumerator()->GetTokenId(
- Top::context()->global()->global_context()->security_token());
+ return entries_.last();
}
@@ -1433,16 +1348,6 @@ int HeapSnapshot::GetObjectSize(HeapObject* obj) {
}
-int HeapSnapshot::GetObjectSecurityToken(HeapObject* obj) {
- if (obj->IsGlobalContext()) {
- return collection_->token_enumerator()->GetTokenId(
- Context::cast(obj)->security_token());
- } else {
- return TokenEnumerator::kNoSecurityToken;
- }
-}
-
-
int HeapSnapshot::CalculateNetworkSize(JSObject* obj) {
int size = obj->Size();
// If 'properties' and 'elements' are non-empty (thus, non-shared),
@@ -1467,15 +1372,10 @@ int HeapSnapshot::CalculateNetworkSize(JSObject* obj) {
}
-class EntriesCollector {
- public:
- explicit EntriesCollector(List<HeapEntry*>* list) : list_(list) { }
- void Apply(HeapEntry* entry) {
- list_->Add(entry);
- }
- private:
- List<HeapEntry*>* list_;
-};
+HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) {
+ return collection_->CompareSnapshots(this, snapshot);
+}
+
template<class T>
static int SortByIds(const T* entry1_ptr,
@@ -1485,22 +1385,16 @@ static int SortByIds(const T* entry1_ptr,
}
List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() {
- if (sorted_entries_ != NULL) return sorted_entries_;
- sorted_entries_ = new List<HeapEntry*>(entries_.capacity());
- EntriesCollector collector(sorted_entries_);
- entries_.Apply(&collector);
- sorted_entries_->Sort(SortByIds);
- return sorted_entries_;
-}
-
-
-HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) {
- return collection_->CompareSnapshots(this, snapshot);
+ if (!entries_sorted_) {
+ entries_.Sort(SortByIds);
+ entries_sorted_ = true;
+ }
+ return &entries_;
}
void HeapSnapshot::Print(int max_depth) {
- root_.Print(max_depth, 0);
+ root()->Print(max_depth, 0);
}
@@ -1635,53 +1529,343 @@ HeapSnapshotsDiff* HeapSnapshotsCollection::CompareSnapshots(
}
+HeapEntriesMap::HeapEntriesMap()
+ : entries_(HeapObjectsMatch),
+ entries_count_(0),
+ total_children_count_(0),
+ total_retainers_count_(0) {
+}
+
+
+HeapEntriesMap::~HeapEntriesMap() {
+ for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) {
+ if (!IsAlias(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));
+ return entry_info->entry;
+ } else {
+ return NULL;
+ }
+}
+
+
+void HeapEntriesMap::Pair(HeapObject* object, HeapEntry* entry) {
+ HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true);
+ ASSERT(cache_entry->value == NULL);
+ cache_entry->value = new EntryInfo(entry);
+ ++entries_count_;
+}
+
+
+void HeapEntriesMap::CountReference(HeapObject* from, HeapObject* to,
+ int* prev_children_count,
+ int* prev_retainers_count) {
+ HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), true);
+ HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false);
+ ASSERT(from_cache_entry != NULL);
+ ASSERT(to_cache_entry != NULL);
+ EntryInfo* from_entry_info =
+ reinterpret_cast<EntryInfo*>(Unalias(from_cache_entry->value));
+ EntryInfo* to_entry_info =
+ reinterpret_cast<EntryInfo*>(Unalias(to_cache_entry->value));
+ if (prev_children_count)
+ *prev_children_count = from_entry_info->children_count;
+ if (prev_retainers_count)
+ *prev_retainers_count = to_entry_info->retainers_count;
+ ++from_entry_info->children_count;
+ ++to_entry_info->retainers_count;
+ ++total_children_count_;
+ ++total_retainers_count_;
+}
+
+
+template<class Visitor>
+void HeapEntriesMap::UpdateEntries(Visitor* visitor) {
+ for (HashMap::Entry* p = entries_.Start();
+ p != NULL;
+ p = entries_.Next(p)) {
+ if (!IsAlias(p->value)) {
+ EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(p->value);
+ entry_info->entry = visitor->GetEntry(
+ reinterpret_cast<HeapObject*>(p->key),
+ entry_info->children_count,
+ entry_info->retainers_count);
+ entry_info->children_count = 0;
+ entry_info->retainers_count = 0;
+ }
+ }
+}
+
+
HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot)
- : snapshot_(snapshot) {
+ : snapshot_(snapshot),
+ collection_(snapshot->collection()),
+ filler_(NULL) {
}
+HeapEntry *const
+HeapSnapshotGenerator::SnapshotFillerInterface::kHeapEntryPlaceholder =
+ reinterpret_cast<HeapEntry*>(1);
+
+class SnapshotCounter : public HeapSnapshotGenerator::SnapshotFillerInterface {
+ public:
+ explicit SnapshotCounter(HeapEntriesMap* entries)
+ : entries_(entries) { }
+ HeapEntry* AddEntry(HeapObject* obj) {
+ entries_->Pair(obj, kHeapEntryPlaceholder);
+ return kHeapEntryPlaceholder;
+ }
+ void SetElementReference(HeapObject* parent_obj,
+ HeapEntry*,
+ int,
+ Object* child_obj,
+ HeapEntry*) {
+ entries_->CountReference(parent_obj, HeapObject::cast(child_obj));
+ }
+ void SetNamedReference(HeapGraphEdge::Type,
+ HeapObject* parent_obj,
+ HeapEntry*,
+ const char*,
+ Object* child_obj,
+ HeapEntry*) {
+ entries_->CountReference(parent_obj, HeapObject::cast(child_obj));
+ }
+ void SetRootReference(Object* child_obj, HeapEntry*) {
+ entries_->CountReference(
+ HeapSnapshot::kInternalRootObject, HeapObject::cast(child_obj));
+ }
+ private:
+ HeapEntriesMap* entries_;
+};
+
+
+class SnapshotFiller : public HeapSnapshotGenerator::SnapshotFillerInterface {
+ public:
+ explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries)
+ : snapshot_(snapshot),
+ collection_(snapshot->collection()),
+ entries_(entries) { }
+ HeapEntry* AddEntry(HeapObject* obj) {
+ UNREACHABLE();
+ return NULL;
+ }
+ void SetElementReference(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);
+ }
+ void SetNamedReference(HeapGraphEdge::Type type,
+ HeapObject* parent_obj,
+ HeapEntry* parent_entry,
+ const char* reference_name,
+ 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->SetNamedReference(type,
+ child_index,
+ reference_name,
+ child_entry,
+ retainer_index);
+ }
+ void SetRootReference(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()->SetElementReference(
+ child_index, child_index + 1, child_entry, retainer_index);
+ }
+ private:
+ HeapSnapshot* snapshot_;
+ HeapSnapshotsCollection* collection_;
+ HeapEntriesMap* entries_;
+};
+
+class SnapshotAllocator {
+ public:
+ explicit SnapshotAllocator(HeapSnapshot* snapshot)
+ : snapshot_(snapshot) { }
+ HeapEntry* GetEntry(
+ HeapObject* obj, int children_count, int retainers_count) {
+ HeapEntry* entry =
+ snapshot_->AddEntry(obj, children_count, retainers_count);
+ ASSERT(entry != NULL);
+ return entry;
+ }
+ private:
+ HeapSnapshot* snapshot_;
+};
+
void HeapSnapshotGenerator::GenerateSnapshot() {
AssertNoAllocation no_alloc;
- // Iterate heap contents.
- HeapIterator iterator;
- for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
+ // Pass 1. Iterate heap contents to count entries and references.
+ SnapshotCounter counter(&entries_);
+ filler_ = &counter;
+ filler_->AddEntry(HeapSnapshot::kInternalRootObject);
+ HeapIterator iterator1;
+ for (HeapObject* obj = iterator1.next();
+ obj != NULL;
+ obj = iterator1.next()) {
ExtractReferences(obj);
}
- snapshot_->CutObjectsFromForeignSecurityContexts();
+ // Allocate and fill entries in the snapshot, allocate references.
+ snapshot_->AllocateEntries(entries_.entries_count(),
+ entries_.total_children_count(),
+ entries_.total_retainers_count());
+ SnapshotAllocator allocator(snapshot_);
+ entries_.UpdateEntries(&allocator);
+
+ // Pass 2. Fill references.
+ SnapshotFiller filler(snapshot_, &entries_);
+ filler_ = &filler;
+ HeapIterator iterator2;
+ for (HeapObject* obj = iterator2.next();
+ obj != NULL;
+ obj = iterator2.next()) {
+ ExtractReferences(obj);
+ }
+}
+
+
+HeapEntry* HeapSnapshotGenerator::GetEntry(Object* obj) {
+ 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);
+ }
+
+ return entry;
+}
+
+
+int HeapSnapshotGenerator::GetGlobalSecurityToken() {
+ return collection_->token_enumerator()->GetTokenId(
+ Top::context()->global()->global_context()->security_token());
+}
+
+
+int HeapSnapshotGenerator::GetObjectSecurityToken(HeapObject* obj) {
+ if (obj->IsGlobalContext()) {
+ return collection_->token_enumerator()->GetTokenId(
+ Context::cast(obj)->security_token());
+ } else {
+ return TokenEnumerator::kNoSecurityToken;
+ }
}
+class IndexedReferencesExtractor : public ObjectVisitor {
+ public:
+ IndexedReferencesExtractor(HeapSnapshotGenerator* generator,
+ HeapObject* parent_obj,
+ HeapEntry* parent_entry)
+ : generator_(generator),
+ parent_obj_(parent_obj),
+ parent_(parent_entry),
+ 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);
+ }
+
+ private:
+ HeapSnapshotGenerator* generator_;
+ HeapObject* parent_obj_;
+ HeapEntry* parent_;
+ int next_index_;
+};
+
+
void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) {
- HeapEntry* entry = snapshot_->GetEntry(obj);
- if (entry == NULL) return;
- if (entry->visited()) return;
+ // We need to reference JS global objects from snapshot's root.
+ // We also need to only include global objects from the current
+ // security context. And we don't want to add the global proxy,
+ // as we don't have a special type for it.
+ if (obj->IsJSGlobalProxy()) {
+ int global_security_token = GetGlobalSecurityToken();
+ JSGlobalProxy* proxy = JSGlobalProxy::cast(obj);
+ int object_security_token =
+ collection_->token_enumerator()->GetTokenId(
+ Context::cast(proxy->context())->security_token());
+ if (object_security_token == TokenEnumerator::kNoSecurityToken
+ || object_security_token == global_security_token) {
+ SetRootReference(proxy->map()->prototype());
+ }
+ return;
+ }
+
+ HeapEntry* entry = GetEntry(obj);
+ if (entry == NULL) return; // No interest in this object.
if (obj->IsJSObject()) {
JSObject* js_obj = JSObject::cast(obj);
ExtractClosureReferences(js_obj, entry);
ExtractPropertyReferences(js_obj, entry);
ExtractElementReferences(js_obj, entry);
- snapshot_->SetPropertyReference(
- entry, Heap::prototype_symbol(), js_obj->map()->prototype());
- } else if (obj->IsJSGlobalPropertyCell()) {
- JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(obj);
- snapshot_->SetElementReference(entry, 0, cell->value());
+ SetPropertyReference(
+ obj, entry, Heap::prototype_symbol(), js_obj->map()->prototype());
} else if (obj->IsString()) {
if (obj->IsConsString()) {
ConsString* cs = ConsString::cast(obj);
- snapshot_->SetElementReference(entry, 0, cs->first());
- snapshot_->SetElementReference(entry, 1, cs->second());
+ SetElementReference(obj, entry, 0, cs->first());
+ SetElementReference(obj, entry, 1, cs->second());
}
} else if (obj->IsCode() || obj->IsSharedFunctionInfo() || obj->IsScript()) {
- IndexedReferencesExtractor refs_extractor(snapshot_, entry);
+ IndexedReferencesExtractor refs_extractor(this, obj, entry);
obj->Iterate(&refs_extractor);
} else if (obj->IsFixedArray()) {
- IndexedReferencesExtractor refs_extractor(snapshot_, entry);
+ IndexedReferencesExtractor refs_extractor(this, obj, entry);
obj->Iterate(&refs_extractor);
}
- entry->MarkAsVisited();
}
@@ -1700,10 +1884,10 @@ void HeapSnapshotGenerator::ExtractClosureReferences(JSObject* js_obj,
String* local_name = *zone_scope_info.LocalName(i);
int idx = serialized_scope_info->ContextSlotIndex(local_name, NULL);
if (idx >= 0 && idx < context->length()) {
- snapshot_->SetClosureReference(entry, local_name, context->get(idx));
+ SetClosureReference(js_obj, entry, local_name, context->get(idx));
}
}
- snapshot_->SetInternalReference(entry, "code", func->shared());
+ SetInternalReference(js_obj, entry, "code", func->shared());
}
}
@@ -1716,13 +1900,13 @@ void HeapSnapshotGenerator::ExtractPropertyReferences(JSObject* js_obj,
switch (descs->GetType(i)) {
case FIELD: {
int index = descs->GetFieldIndex(i);
- snapshot_->SetPropertyReference(
- entry, descs->GetKey(i), js_obj->FastPropertyAt(index));
+ SetPropertyReference(
+ js_obj, entry, descs->GetKey(i), js_obj->FastPropertyAt(index));
break;
}
case CONSTANT_FUNCTION:
- snapshot_->SetPropertyReference(
- entry, descs->GetKey(i), descs->GetConstantFunction(i));
+ SetPropertyReference(
+ js_obj, entry, descs->GetKey(i), descs->GetConstantFunction(i));
break;
default: ;
}
@@ -1733,8 +1917,8 @@ void HeapSnapshotGenerator::ExtractPropertyReferences(JSObject* js_obj,
for (int i = 0; i < length; ++i) {
Object* k = dictionary->KeyAt(i);
if (dictionary->IsKey(k)) {
- snapshot_->SetPropertyReference(
- entry, String::cast(k), dictionary->ValueAt(i));
+ SetPropertyReference(
+ js_obj, entry, String::cast(k), dictionary->ValueAt(i));
}
}
}
@@ -1750,7 +1934,7 @@ void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj,
elements->length();
for (int i = 0; i < length; ++i) {
if (!elements->get(i)->IsTheHole()) {
- snapshot_->SetElementReference(entry, i, elements->get(i));
+ SetElementReference(js_obj, entry, i, elements->get(i));
}
}
} else if (js_obj->HasDictionaryElements()) {
@@ -1761,13 +1945,90 @@ void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj,
if (dictionary->IsKey(k)) {
ASSERT(k->IsNumber());
uint32_t index = static_cast<uint32_t>(k->Number());
- snapshot_->SetElementReference(entry, index, dictionary->ValueAt(i));
+ SetElementReference(js_obj, entry, index, dictionary->ValueAt(i));
}
}
}
}
+void HeapSnapshotGenerator::SetClosureReference(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::kContextVariable,
+ parent_obj,
+ parent_entry,
+ collection_->GetName(reference_name),
+ child_obj,
+ child_entry);
+ }
+}
+
+
+void HeapSnapshotGenerator::SetElementReference(HeapObject* parent_obj,
+ HeapEntry* parent_entry,
+ int index,
+ Object* child_obj) {
+ HeapEntry* child_entry = GetEntry(child_obj);
+ if (child_entry != NULL) {
+ filler_->SetElementReference(
+ parent_obj, parent_entry, index, child_obj, child_entry);
+ }
+}
+
+
+void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj,
+ HeapEntry* parent_entry,
+ const char* reference_name,
+ Object* child_obj) {
+ HeapEntry* child_entry = GetEntry(child_obj);
+ if (child_entry != NULL) {
+ filler_->SetNamedReference(HeapGraphEdge::kInternal,
+ parent_obj,
+ parent_entry,
+ reference_name,
+ child_obj,
+ child_entry);
+ }
+}
+
+
+void HeapSnapshotGenerator::SetPropertyReference(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::kProperty,
+ parent_obj,
+ parent_entry,
+ collection_->GetName(reference_name),
+ child_obj,
+ child_entry);
+ }
+}
+
+
+void HeapSnapshotGenerator::SetRootReference(Object* child_obj) {
+ HeapEntry* child_entry = GetEntry(child_obj);
+ ASSERT(child_entry != NULL);
+ filler_->SetRootReference(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_, additions_count, 0);
+ raw_deletions_root_ =
+ NewArray<char>(HeapEntry::EntriesSize(1, deletions_count, 0));
+ deletions_root()->Init(snapshot1_, deletions_count, 0);
+}
+
+
static void DeleteHeapSnapshotsDiff(HeapSnapshotsDiff** diff_ptr) {
delete *diff_ptr;
}
@@ -1779,8 +2040,6 @@ HeapSnapshotsComparator::~HeapSnapshotsComparator() {
HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1,
HeapSnapshot* snapshot2) {
- HeapSnapshotsDiff* diff = new HeapSnapshotsDiff(snapshot1, snapshot2);
- diffs_.Add(diff);
List<HeapEntry*>* entries1 = snapshot1->GetSortedEntriesList();
List<HeapEntry*>* entries2 = snapshot2->GetSortedEntriesList();
int i = 0, j = 0;
@@ -1810,17 +2069,33 @@ HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1,
snapshot1->ClearPaint();
snapshot1->root()->PaintAllReachable();
+ snapshot2->ClearPaint();
+ snapshot2->root()->PaintAllReachable();
+ int reachable_deleted_entries = 0, reachable_added_entries = 0;
+ for (int i = 0; i < deleted_entries.length(); ++i) {
+ HeapEntry* entry = deleted_entries[i];
+ if (entry->painted_reachable()) ++reachable_deleted_entries;
+ }
+ for (int i = 0; i < added_entries.length(); ++i) {
+ HeapEntry* entry = added_entries[i];
+ if (entry->painted_reachable()) ++reachable_added_entries;
+ }
+
+ HeapSnapshotsDiff* diff = new HeapSnapshotsDiff(snapshot1, snapshot2);
+ diffs_.Add(diff);
+ diff->CreateRoots(reachable_added_entries, reachable_deleted_entries);
+
+ int del_child_index = 0, deleted_entry_index = 1;
for (int i = 0; i < deleted_entries.length(); ++i) {
HeapEntry* entry = deleted_entries[i];
if (entry->painted_reachable())
- diff->AddDeletedEntry(entry);
+ diff->AddDeletedEntry(del_child_index++, deleted_entry_index++, entry);
}
- snapshot2->ClearPaint();
- snapshot2->root()->PaintAllReachable();
+ int add_child_index = 0, added_entry_index = 1;
for (int i = 0; i < added_entries.length(); ++i) {
HeapEntry* entry = added_entries[i];
if (entry->painted_reachable())
- diff->AddAddedEntry(entry);
+ diff->AddAddedEntry(add_child_index++, added_entry_index++, entry);
}
return diff;
}
« 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