From: loislo@chromium.org Date: Wed, 23 May 2012 05:27:08 +0000 (+0000) Subject: Eliminate dominator and retained_size fields. They are calculating on front-end side... X-Git-Tag: upstream/4.7.83~16677 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=610ef68f063c7f4ea9494ad6cb144f48fb862308;p=platform%2Fupstream%2Fv8.git Eliminate dominator and retained_size fields. They are calculating on front-end side. See meta-bug https://bugs.webkit.org/show_bug.cgi?id=87089 BUG=none TEST=none Review URL: https://chromiumcodereview.appspot.com/10416035 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11626 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/api.cc b/src/api.cc index 52a84ed..b43aaf3 100644 --- a/src/api.cc +++ b/src/api.cc @@ -6045,13 +6045,6 @@ int HeapGraphNode::GetSelfSize() const { } -int HeapGraphNode::GetRetainedSize() const { - i::Isolate* isolate = i::Isolate::Current(); - IsDeadCheck(isolate, "v8::HeapSnapshot::GetRetainedSize"); - return ToInternal(this)->retained_size(); -} - - int HeapGraphNode::GetChildrenCount() const { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapSnapshot::GetChildrenCount"); @@ -6067,28 +6060,6 @@ const HeapGraphEdge* HeapGraphNode::GetChild(int index) const { } -int HeapGraphNode::GetRetainersCount() const { - i::Isolate* isolate = i::Isolate::Current(); - IsDeadCheck(isolate, "v8::HeapSnapshot::GetRetainersCount"); - return ToInternal(this)->retainers().length(); -} - - -const HeapGraphEdge* HeapGraphNode::GetRetainer(int index) const { - i::Isolate* isolate = i::Isolate::Current(); - IsDeadCheck(isolate, "v8::HeapSnapshot::GetRetainer"); - return reinterpret_cast( - ToInternal(this)->retainers()[index]); -} - - -const HeapGraphNode* HeapGraphNode::GetDominatorNode() const { - i::Isolate* isolate = i::Isolate::Current(); - IsDeadCheck(isolate, "v8::HeapSnapshot::GetDominatorNode"); - return reinterpret_cast(ToInternal(this)->dominator()); -} - - v8::Handle HeapGraphNode::GetHeapValue() const { i::Isolate* isolate = i::Isolate::Current(); IsDeadCheck(isolate, "v8::HeapGraphNode::GetHeapValue"); diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h index 9afc52f..6c64350 100644 --- a/src/profile-generator-inl.h +++ b/src/profile-generator-inl.h @@ -118,32 +118,12 @@ int HeapEntry::set_children_index(int index) { } -int HeapEntry::set_retainers_index(int index) { - retainers_index_ = index; - int next_index = index + retainers_count_; - retainers_count_ = 0; - return next_index; -} - - HeapGraphEdge** HeapEntry::children_arr() { ASSERT(children_index_ >= 0); return &snapshot_->children()[children_index_]; } -HeapGraphEdge** HeapEntry::retainers_arr() { - ASSERT(retainers_index_ >= 0); - return &snapshot_->retainers()[retainers_index_]; -} - - -HeapEntry* HeapEntry::dominator() const { - ASSERT(dominator_ >= 0); - return &snapshot_->entries()[dominator_]; -} - - SnapshotObjectId HeapObjectsMap::GetNthGcSubrootId(int delta) { return kGcRootsFirstSubrootId + delta * kObjectIdStep; } diff --git a/src/profile-generator.cc b/src/profile-generator.cc index da2a969..b670d4e 100644 --- a/src/profile-generator.cc +++ b/src/profile-generator.cc @@ -964,16 +964,10 @@ HeapEntry::HeapEntry(HeapSnapshot* snapshot, const char* name, SnapshotObjectId id, int self_size) - : painted_(false), - user_reachable_(false), - dominator_(kNoEntry), - type_(type), - retainers_count_(0), - retainers_index_(-1), + : type_(type), children_count_(0), children_index_(-1), self_size_(self_size), - retained_size_(0), id_(id), snapshot_(snapshot), name_(name) { } @@ -985,7 +979,6 @@ void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, HeapGraphEdge edge(type, name, this->index(), entry->index()); snapshot_->edges().Add(edge); ++children_count_; - ++entry->retainers_count_; } @@ -995,7 +988,6 @@ void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, HeapGraphEdge edge(type, index, this->index(), entry->index()); snapshot_->edges().Add(edge); ++children_count_; - ++entry->retainers_count_; } @@ -1007,9 +999,8 @@ Handle HeapEntry::GetHeapObject() { void HeapEntry::Print( const char* prefix, const char* edge_name, int max_depth, int indent) { STATIC_CHECK(sizeof(unsigned) == sizeof(id())); - OS::Print("%6d %7d @%6u %*c %s%s: ", - self_size(), retained_size(), id(), - indent, ' ', prefix, edge_name); + OS::Print("%6d @%6u %*c %s%s: ", + self_size(), id(), indent, ' ', prefix, edge_name); if (type() != kString) { OS::Print("%s %.40s\n", TypeAsString(), name_); } else { @@ -1091,13 +1082,13 @@ template struct SnapshotSizeConstants; template <> struct SnapshotSizeConstants<4> { static const int kExpectedHeapGraphEdgeSize = 12; - static const int kExpectedHeapEntrySize = 40; + static const int kExpectedHeapEntrySize = 24; static const size_t kMaxSerializableSnapshotRawSize = 256 * MB; }; template <> struct SnapshotSizeConstants<8> { static const int kExpectedHeapGraphEdgeSize = 24; - static const int kExpectedHeapEntrySize = 48; + static const int kExpectedHeapEntrySize = 32; static const uint64_t kMaxSerializableSnapshotRawSize = static_cast(6000) * MB; }; @@ -1139,16 +1130,6 @@ void HeapSnapshot::RememberLastJSObjectId() { } -static void HeapEntryClearPaint(HeapEntry* entry_ptr) { - entry_ptr->clear_paint(); -} - - -void HeapSnapshot::ClearPaint() { - entries_.Iterate(HeapEntryClearPaint); -} - - HeapEntry* HeapSnapshot::AddRootEntry() { ASSERT(root_index_ == HeapEntry::kNoEntry); ASSERT(entries_.is_empty()); // Root entry must be the first one. @@ -1196,32 +1177,19 @@ HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, } -void HeapSnapshot::FillChildrenAndRetainers() { +void HeapSnapshot::FillChildren() { ASSERT(children().is_empty()); children().Allocate(edges().length()); - ASSERT(retainers().is_empty()); - retainers().Allocate(edges().length()); int children_index = 0; - int retainers_index = 0; for (int i = 0; i < entries().length(); ++i) { HeapEntry* entry = &entries()[i]; children_index = entry->set_children_index(children_index); - retainers_index = entry->set_retainers_index(retainers_index); } ASSERT(edges().length() == children_index); - ASSERT(edges().length() == retainers_index); for (int i = 0; i < edges().length(); ++i) { HeapGraphEdge* edge = &edges()[i]; edge->ReplaceToIndexWithEntry(this); edge->from()->add_child(edge); - edge->to()->add_retainer(edge); - } -} - - -void HeapSnapshot::SetDominatorsToSelf() { - for (int i = 0; i < entries_.length(); ++i) { - entries_[i].set_dominator(&entries_[i]); } } @@ -1284,7 +1252,6 @@ size_t HeapSnapshot::RawSnapshotSize() const { GetMemoryUsedByList(entries_) + GetMemoryUsedByList(edges_) + GetMemoryUsedByList(children_) + - GetMemoryUsedByList(retainers_) + GetMemoryUsedByList(sorted_entries_); } @@ -3091,12 +3058,9 @@ bool HeapSnapshotGenerator::GenerateSnapshot() { if (!FillReferences()) return false; - snapshot_->FillChildrenAndRetainers(); + snapshot_->FillChildren(); snapshot_->RememberLastJSObjectId(); - if (!SetEntriesDominators()) return false; - if (!CalculateRetainedSizes()) return false; - progress_counter_ = progress_total_; if (!ProgressReport(true)) return false; return true; @@ -3138,187 +3102,6 @@ bool HeapSnapshotGenerator::FillReferences() { } -bool HeapSnapshotGenerator::IsUserGlobalReference(const HeapGraphEdge* edge) { - ASSERT(edge->from() == snapshot_->root()); - return edge->type() == HeapGraphEdge::kShortcut; -} - - -void HeapSnapshotGenerator::MarkUserReachableObjects() { - List worklist; - - Vector children = snapshot_->root()->children(); - for (int i = 0; i < children.length(); ++i) { - if (IsUserGlobalReference(children[i])) { - worklist.Add(children[i]->to()); - } - } - - while (!worklist.is_empty()) { - HeapEntry* entry = worklist.RemoveLast(); - if (entry->user_reachable()) continue; - entry->set_user_reachable(); - Vector children = entry->children(); - for (int i = 0; i < children.length(); ++i) { - HeapEntry* child = children[i]->to(); - if (!child->user_reachable()) { - worklist.Add(child); - } - } - } -} - - -static bool IsRetainingEdge(HeapGraphEdge* edge) { - if (edge->type() == HeapGraphEdge::kShortcut) return false; - // The edge is not retaining if it goes from system domain - // (i.e. an object not reachable from window) to the user domain - // (i.e. a reachable object). - return edge->from()->user_reachable() - || !edge->to()->user_reachable(); -} - - -void HeapSnapshotGenerator::FillPostorderIndexes( - Vector* entries) { - snapshot_->ClearPaint(); - int current_entry = 0; - List nodes_to_visit; - HeapEntry* root = snapshot_->root(); - nodes_to_visit.Add(root); - snapshot_->root()->paint(); - while (!nodes_to_visit.is_empty()) { - HeapEntry* entry = nodes_to_visit.last(); - Vector children = entry->children(); - bool has_new_edges = false; - for (int i = 0; i < children.length(); ++i) { - if (entry != root && !IsRetainingEdge(children[i])) continue; - HeapEntry* child = children[i]->to(); - if (!child->painted()) { - nodes_to_visit.Add(child); - child->paint(); - has_new_edges = true; - } - } - if (!has_new_edges) { - entry->set_postorder_index(current_entry); - (*entries)[current_entry++] = entry; - nodes_to_visit.RemoveLast(); - } - } - ASSERT_EQ(current_entry, entries->length()); -} - - -static int Intersect(int i1, int i2, const Vector& dominators) { - int finger1 = i1, finger2 = i2; - while (finger1 != finger2) { - while (finger1 < finger2) finger1 = dominators[finger1]; - while (finger2 < finger1) finger2 = dominators[finger2]; - } - 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. -bool HeapSnapshotGenerator::BuildDominatorTree( - const Vector& entries, - Vector* dominators) { - if (entries.length() == 0) return true; - HeapEntry* root = snapshot_->root(); - const int entries_length = entries.length(), root_index = entries_length - 1; - for (int i = 0; i < root_index; ++i) (*dominators)[i] = HeapEntry::kNoEntry; - (*dominators)[root_index] = root_index; - - // The affected array is used to mark entries which dominators - // have to be racalculated because of changes in their retainers. - ScopedVector affected(entries_length); - for (int i = 0; i < affected.length(); ++i) affected[i] = false; - // Mark the root direct children as affected. - Vector children = entries[root_index]->children(); - for (int i = 0; i < children.length(); ++i) { - affected[children[i]->to()->postorder_index()] = true; - } - - bool changed = true; - while (changed) { - changed = false; - if (!ProgressReport(false)) return false; - for (int i = root_index - 1; i >= 0; --i) { - if (!affected[i]) continue; - affected[i] = false; - // If dominator of the entry has already been set to root, - // then it can't propagate any further. - if ((*dominators)[i] == root_index) continue; - int new_idom_index = HeapEntry::kNoEntry; - Vector rets = entries[i]->retainers(); - for (int j = 0; j < rets.length(); ++j) { - if (rets[j]->from() != root && !IsRetainingEdge(rets[j])) continue; - int ret_index = rets[j]->from()->postorder_index(); - if (dominators->at(ret_index) != HeapEntry::kNoEntry) { - new_idom_index = new_idom_index == HeapEntry::kNoEntry - ? ret_index - : Intersect(ret_index, new_idom_index, *dominators); - // If idom has already reached the root, it doesn't make sense - // to check other retainers. - if (new_idom_index == root_index) break; - } - } - if (new_idom_index != HeapEntry::kNoEntry - && dominators->at(i) != new_idom_index) { - (*dominators)[i] = new_idom_index; - changed = true; - Vector children = entries[i]->children(); - for (int j = 0; j < children.length(); ++j) { - affected[children[j]->to()->postorder_index()] = true; - } - } - } - } - return true; -} - - -bool HeapSnapshotGenerator::SetEntriesDominators() { - MarkUserReachableObjects(); - // This array is used for maintaining postorder of nodes. - ScopedVector ordered_entries(snapshot_->entries().length()); - FillPostorderIndexes(&ordered_entries); - ScopedVector dominators(ordered_entries.length()); - if (!BuildDominatorTree(ordered_entries, &dominators)) return false; - for (int i = 0; i < ordered_entries.length(); ++i) { - ASSERT(dominators[i] != HeapEntry::kNoEntry); - ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]); - } - return true; -} - - -bool HeapSnapshotGenerator::CalculateRetainedSizes() { - // As for the dominators tree we only know parent nodes, not - // children, to sum up total sizes we "bubble" node's self size - // adding it to all of its parents. - List& entries = snapshot_->entries(); - for (int i = 0; i < entries.length(); ++i) { - HeapEntry* entry = &entries[i]; - entry->set_retained_size(entry->self_size()); - } - for (int i = 0; i < entries.length(); ++i) { - int entry_size = entries[i].self_size(); - HeapEntry* current = &entries[i]; - for (HeapEntry* dominator = current->dominator(); - dominator != current; - current = dominator, dominator = current->dominator()) { - ASSERT(current->dominator() != NULL); - dominator->add_retained_size(entry_size); - } - } - return true; -} - - template struct MaxDecimalDigitsIn; template<> struct MaxDecimalDigitsIn<4> { static const int kSigned = 11; @@ -3417,8 +3200,8 @@ class OutputStreamWriter { // type, name|index, to_node. const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3; -// type, name, id, self_size, retained_size, dominator, children_index. -const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 7; +// type, name, id, self_size, children_index. +const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 5; void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { ASSERT(writer_ == NULL); @@ -3458,8 +3241,7 @@ HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() { (snapshot_->RawSnapshotSize() + MB - 1) / MB); HeapEntry* message = result->AddEntry(HeapEntry::kString, text, 0, 4); result->root()->SetIndexedReference(HeapGraphEdge::kElement, 1, message); - result->FillChildrenAndRetainers(); - result->SetDominatorsToSelf(); + result->FillChildren(); return result; } @@ -3557,11 +3339,10 @@ void HeapSnapshotJSONSerializer::SerializeEdges(const List& nodes) { void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry, int edges_index) { - // The buffer needs space for 6 ints, 1 uint32_t, 7 commas, \n and \0 + // The buffer needs space for 5 uint32_t, 5 commas, \n and \0 static const int kBufferSize = - 6 * MaxDecimalDigitsIn::kSigned // NOLINT - + MaxDecimalDigitsIn::kUnsigned // NOLINT - + 7 + 1 + 1; + 5 * MaxDecimalDigitsIn::kUnsigned // NOLINT + + 5 + 1 + 1; EmbeddedVector buffer; int buffer_pos = 0; if (entry_index(entry) != 0) { @@ -3575,10 +3356,6 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry, buffer[buffer_pos++] = ','; buffer_pos = utoa(entry->self_size(), buffer, buffer_pos); buffer[buffer_pos++] = ','; - buffer_pos = utoa(entry->retained_size(), buffer, buffer_pos); - buffer[buffer_pos++] = ','; - buffer_pos = utoa(entry_index(entry->dominator()), buffer, buffer_pos); - buffer[buffer_pos++] = ','; buffer_pos = utoa(edges_index, buffer, buffer_pos); buffer[buffer_pos++] = '\n'; buffer[buffer_pos++] = '\0'; @@ -3615,8 +3392,6 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() { JSON_S("name") "," JSON_S("id") "," JSON_S("self_size") "," - JSON_S("retained_size") "," - JSON_S("dominator") "," JSON_S("edges_index")) "," JSON_S("node_types") ":" JSON_A( JSON_A( diff --git a/src/profile-generator.h b/src/profile-generator.h index 92896c2..349226b 100644 --- a/src/profile-generator.h +++ b/src/profile-generator.h @@ -529,35 +529,14 @@ class HeapEntry BASE_EMBEDDED { void set_name(const char* name) { name_ = name; } inline SnapshotObjectId id() { return id_; } int self_size() { return self_size_; } - int retained_size() { return retained_size_; } - void add_retained_size(int size) { retained_size_ += size; } - void set_retained_size(int size) { retained_size_ = size; } INLINE(int index() const); - int postorder_index() { return postorder_index_; } - void set_postorder_index(int value) { postorder_index_ = value; } int children_count() const { return children_count_; } INLINE(int set_children_index(int index)); - INLINE(int set_retainers_index(int index)); void add_child(HeapGraphEdge* edge) { children_arr()[children_count_++] = edge; } - void add_retainer(HeapGraphEdge* edge) { - retainers_arr()[retainers_count_++] = edge; - } Vector children() { return Vector(children_arr(), children_count_); } - Vector retainers() { - return Vector(retainers_arr(), retainers_count_); } - INLINE(HeapEntry* dominator() const); - void set_dominator(HeapEntry* entry) { - ASSERT(entry != NULL); - dominator_ = entry->index(); - } - void clear_paint() { painted_ = false; } - bool painted() { return painted_; } - void paint() { painted_ = true; } - bool user_reachable() { return user_reachable_; } - void set_user_reachable() { user_reachable_ = true; } void SetIndexedReference( HeapGraphEdge::Type type, int index, HeapEntry* entry); @@ -571,22 +550,12 @@ class HeapEntry BASE_EMBEDDED { private: INLINE(HeapGraphEdge** children_arr()); - INLINE(HeapGraphEdge** retainers_arr()); const char* TypeAsString(); - unsigned painted_: 1; - unsigned user_reachable_: 1; - int dominator_: 30; unsigned type_: 4; - int retainers_count_: 28; - int retainers_index_; - int children_count_; + int children_count_: 28; int children_index_; int self_size_; - union { - int postorder_index_; // Used during dominator tree building. - int retained_size_; // At that moment, there is no retained size yet. - }; SnapshotObjectId id_; HeapSnapshot* snapshot_; const char* name_; @@ -626,7 +595,6 @@ class HeapSnapshot { List& entries() { return entries_; } List& edges() { return edges_; } List& children() { return children_; } - List& retainers() { return retainers_; } void RememberLastJSObjectId(); SnapshotObjectId max_snapshot_js_object_id() const { return max_snapshot_js_object_id_; @@ -640,11 +608,9 @@ class HeapSnapshot { HeapEntry* AddGcRootsEntry(); HeapEntry* AddGcSubrootEntry(int tag); HeapEntry* AddNativesRootEntry(); - void ClearPaint(); HeapEntry* GetEntryById(SnapshotObjectId id); List* GetSortedEntriesList(); - void SetDominatorsToSelf(); - void FillChildrenAndRetainers(); + void FillChildren(); void Print(int max_depth); void PrintEntriesSize(); @@ -661,7 +627,6 @@ class HeapSnapshot { List entries_; List edges_; List children_; - List retainers_; List sorted_entries_; SnapshotObjectId max_snapshot_js_object_id_; @@ -1061,16 +1026,9 @@ class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface { bool GenerateSnapshot(); private: - bool BuildDominatorTree(const Vector& entries, - Vector* dominators); - bool CalculateRetainedSizes(); bool FillReferences(); - void FillPostorderIndexes(Vector* entries); - bool IsUserGlobalReference(const HeapGraphEdge* edge); - void MarkUserReachableObjects(); void ProgressStep(); bool ProgressReport(bool force = false); - bool SetEntriesDominators(); void SetProgressTotal(int iterations_count); HeapSnapshot* snapshot_; diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc index cbe8d44..c405b33 100644 --- a/test/cctest/test-heap-profiler.cc +++ b/test/cctest/test-heap-profiler.cc @@ -7,6 +7,7 @@ #include "v8.h" #include "cctest.h" +#include "hashmap.h" #include "heap-profiler.h" #include "snapshot.h" #include "debug.h" @@ -27,10 +28,14 @@ class NamedEntriesDetector { if (strcmp(entry->name(), "C2") == 0) has_C2 = true; } + static bool AddressesMatch(void* key1, void* key2) { + return key1 == key2; + } + void CheckAllReachables(i::HeapEntry* root) { + i::HashMap visited(AddressesMatch); i::List list(10); list.Add(root); - root->paint(); CheckEntry(root); while (!list.is_empty()) { i::HeapEntry* entry = list.RemoveLast(); @@ -38,11 +43,15 @@ class NamedEntriesDetector { for (int i = 0; i < children.length(); ++i) { if (children[i]->type() == i::HeapGraphEdge::kShortcut) continue; i::HeapEntry* child = children[i]->to(); - if (!child->painted()) { - list.Add(child); - child->paint(); - CheckEntry(child); - } + i::HashMap::Entry* entry = visited.Lookup( + reinterpret_cast(child), + static_cast(reinterpret_cast(child)), + true); + if (entry->value) + continue; + entry->value = reinterpret_cast(1); + list.Add(child); + CheckEntry(child); } } } @@ -105,9 +114,6 @@ TEST(HeapSnapshot) { "var c2 = new C2(a2);"); const v8::HeapSnapshot* snapshot_env2 = v8::HeapProfiler::TakeSnapshot(v8_str("env2")); - i::HeapSnapshot* i_snapshot_env2 = - const_cast( - reinterpret_cast(snapshot_env2)); const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2); // Verify, that JS global object of env2 has '..2' properties. @@ -120,9 +126,7 @@ TEST(HeapSnapshot) { NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_2")); CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c2")); - // Paint all nodes reachable from global object. NamedEntriesDetector det; - i_snapshot_env2->ClearPaint(); det.CheckAllReachables(const_cast( reinterpret_cast(global_env2))); CHECK(det.has_A2); @@ -156,9 +160,9 @@ TEST(HeapSnapshotObjectSizes) { CHECK_NE(NULL, x2); // Test sizes. - CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize()); - CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize()); - CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize()); + CHECK_NE(0, x->GetSelfSize()); + CHECK_NE(0, x1->GetSelfSize()); + CHECK_NE(0, x2->GetSelfSize()); } @@ -477,66 +481,6 @@ TEST(HeapSnapshotRootPreservedAfterSorting) { } -TEST(HeapEntryDominator) { - // The graph looks like this: - // - // -> node1 - // a |^ - // -> node5 ba - // a v| - // node6 -> node2 - // b a |^ - // -> node4 ba - // b v| - // -> node3 - // - // The dominator for all nodes is node6. - - v8::HandleScope scope; - LocalContext env; - - CompileRun( - "function X(a, b) { this.a = a; this.b = b; }\n" - "node6 = new X(new X(new X()), new X(new X(),new X()));\n" - "(function(){\n" - "node6.a.a.b = node6.b.a; // node1 -> node2\n" - "node6.b.a.a = node6.a.a; // node2 -> node1\n" - "node6.b.a.b = node6.b.b; // node2 -> node3\n" - "node6.b.b.a = node6.b.a; // node3 -> node2\n" - "})();"); - - const v8::HeapSnapshot* snapshot = - v8::HeapProfiler::TakeSnapshot(v8_str("dominators")); - - const v8::HeapGraphNode* global = GetGlobalObject(snapshot); - CHECK_NE(NULL, global); - const v8::HeapGraphNode* node6 = - GetProperty(global, v8::HeapGraphEdge::kProperty, "node6"); - CHECK_NE(NULL, node6); - const v8::HeapGraphNode* node5 = - GetProperty(node6, v8::HeapGraphEdge::kProperty, "a"); - CHECK_NE(NULL, node5); - const v8::HeapGraphNode* node4 = - GetProperty(node6, v8::HeapGraphEdge::kProperty, "b"); - CHECK_NE(NULL, node4); - const v8::HeapGraphNode* node3 = - GetProperty(node4, v8::HeapGraphEdge::kProperty, "b"); - CHECK_NE(NULL, node3); - const v8::HeapGraphNode* node2 = - GetProperty(node4, v8::HeapGraphEdge::kProperty, "a"); - CHECK_NE(NULL, node2); - const v8::HeapGraphNode* node1 = - GetProperty(node5, v8::HeapGraphEdge::kProperty, "a"); - CHECK_NE(NULL, node1); - - CHECK_EQ(node6, node1->GetDominatorNode()); - CHECK_EQ(node6, node2->GetDominatorNode()); - CHECK_EQ(node6, node3->GetDominatorNode()); - CHECK_EQ(node6, node4->GetDominatorNode()); - CHECK_EQ(node6, node5->GetDominatorNode()); -} - - namespace { class TestJSONStream : public v8::OutputStream {