Eliminate dominator and retained_size fields. They are calculating on front-end side...
authorloislo@chromium.org <loislo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 23 May 2012 05:27:08 +0000 (05:27 +0000)
committerloislo@chromium.org <loislo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 23 May 2012 05:27:08 +0000 (05:27 +0000)
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

src/api.cc
src/profile-generator-inl.h
src/profile-generator.cc
src/profile-generator.h
test/cctest/test-heap-profiler.cc

index 52a84ed..b43aaf3 100644 (file)
@@ -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<const HeapGraphEdge*>(
-      ToInternal(this)->retainers()[index]);
-}
-
-
-const HeapGraphNode* HeapGraphNode::GetDominatorNode() const {
-  i::Isolate* isolate = i::Isolate::Current();
-  IsDeadCheck(isolate, "v8::HeapSnapshot::GetDominatorNode");
-  return reinterpret_cast<const HeapGraphNode*>(ToInternal(this)->dominator());
-}
-
-
 v8::Handle<v8::Value> HeapGraphNode::GetHeapValue() const {
   i::Isolate* isolate = i::Isolate::Current();
   IsDeadCheck(isolate, "v8::HeapGraphNode::GetHeapValue");
index 9afc52f..6c64350 100644 (file)
@@ -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;
 }
index da2a969..b670d4e 100644 (file)
@@ -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<HeapObject> 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 <size_t ptr_size> 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<uint64_t>(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<HeapEntry*> worklist;
-
-  Vector<HeapGraphEdge*> 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<HeapGraphEdge*> 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<HeapEntry*>* entries) {
-  snapshot_->ClearPaint();
-  int current_entry = 0;
-  List<HeapEntry*> 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<HeapGraphEdge*> 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<int>& 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<HeapEntry*>& entries,
-    Vector<int>* 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<bool> affected(entries_length);
-  for (int i = 0; i < affected.length(); ++i) affected[i] = false;
-  // Mark the root direct children as affected.
-  Vector<HeapGraphEdge*> 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<HeapGraphEdge*> 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<HeapGraphEdge*> 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<HeapEntry*> ordered_entries(snapshot_->entries().length());
-  FillPostorderIndexes(&ordered_entries);
-  ScopedVector<int> 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<HeapEntry>& 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<int bytes> 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<HeapEntry>& 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<sizeof(int)>::kSigned  // NOLINT
-      + MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned  // NOLINT
-      + 7 + 1 + 1;
+      5 * MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned  // NOLINT
+      + 5 + 1 + 1;
   EmbeddedVector<char, kBufferSize> 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(
index 92896c2..349226b 100644 (file)
@@ -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<HeapGraphEdge*> children() {
     return Vector<HeapGraphEdge*>(children_arr(), children_count_); }
-  Vector<HeapGraphEdge*> retainers() {
-    return Vector<HeapGraphEdge*>(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<HeapEntry>& entries() { return entries_; }
   List<HeapGraphEdge>& edges() { return edges_; }
   List<HeapGraphEdge*>& children() { return children_; }
-  List<HeapGraphEdge*>& 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<HeapEntry*>* GetSortedEntriesList();
-  void SetDominatorsToSelf();
-  void FillChildrenAndRetainers();
+  void FillChildren();
 
   void Print(int max_depth);
   void PrintEntriesSize();
@@ -661,7 +627,6 @@ class HeapSnapshot {
   List<HeapEntry> entries_;
   List<HeapGraphEdge> edges_;
   List<HeapGraphEdge*> children_;
-  List<HeapGraphEdge*> retainers_;
   List<HeapEntry*> sorted_entries_;
   SnapshotObjectId max_snapshot_js_object_id_;
 
@@ -1061,16 +1026,9 @@ class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
   bool GenerateSnapshot();
 
  private:
-  bool BuildDominatorTree(const Vector<HeapEntry*>& entries,
-                          Vector<int>* dominators);
-  bool CalculateRetainedSizes();
   bool FillReferences();
-  void FillPostorderIndexes(Vector<HeapEntry*>* entries);
-  bool IsUserGlobalReference(const HeapGraphEdge* edge);
-  void MarkUserReachableObjects();
   void ProgressStep();
   bool ProgressReport(bool force = false);
-  bool SetEntriesDominators();
   void SetProgressTotal(int iterations_count);
 
   HeapSnapshot* snapshot_;
index cbe8d44..c405b33 100644 (file)
@@ -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<i::HeapEntry*> 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<void*>(child),
+            static_cast<uint32_t>(reinterpret_cast<uintptr_t>(child)),
+            true);
+        if (entry->value)
+          continue;
+        entry->value = reinterpret_cast<void*>(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<i::HeapSnapshot*>(
-          reinterpret_cast<const i::HeapSnapshot*>(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<i::HeapEntry*>(
       reinterpret_cast<const i::HeapEntry*>(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 {