Revision: 6091
Author: [email protected]
Date: Tue Dec 21 02:49:40 2010
Log: Implement HeapIterator that skips over unreachable objects.

I'm using it when creating heap snapshots. I decided that it will
be more convenient to have it as a separate piece of code, instead
of embedding into the snapshot generator.

Review URL: http://codereview.chromium.org/6014004
http://code.google.com/p/v8/source/detail?r=6091

Modified:
 /branches/bleeding_edge/src/heap-profiler.cc
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/profile-generator.cc
 /branches/bleeding_edge/test/cctest/test-heap.cc

=======================================
--- /branches/bleeding_edge/src/heap-profiler.cc        Wed Dec 15 00:07:27 2010
+++ /branches/bleeding_edge/src/heap-profiler.cc        Tue Dec 21 02:49:40 2010
@@ -367,7 +367,6 @@
 HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name,
                                              int type,
v8::ActivityControl* control) {
-  Heap::CollectAllGarbage(true);
   HeapSnapshot::Type s_type = static_cast<HeapSnapshot::Type>(type);
   HeapSnapshot* result =
       snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++);
@@ -379,6 +378,7 @@
       break;
     }
     case HeapSnapshot::kAggregated: {
+      Heap::CollectAllGarbage(true);
       AggregatedHeapSnapshot agg_snapshot;
       AggregatedHeapSnapshotGenerator generator(&agg_snapshot);
       generator.GenerateSnapshot();
@@ -808,7 +808,7 @@


 void AggregatedHeapSnapshotGenerator::GenerateSnapshot() {
-  HeapIterator iterator(HeapIterator::kPreciseFiltering);
+  HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
     CollectStats(obj);
     agg_snapshot_->js_cons_profile()->CollectStats(obj);
=======================================
--- /branches/bleeding_edge/src/heap.cc Mon Dec 13 04:14:30 2010
+++ /branches/bleeding_edge/src/heap.cc Tue Dec 21 02:49:40 2010
@@ -4483,7 +4483,7 @@
       MemoryAllocator::Size() + MemoryAllocator::Available();
   *stats->os_error = OS::GetLastError();
   if (take_snapshot) {
-    HeapIterator iterator(HeapIterator::kPreciseFiltering);
+    HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
     for (HeapObject* obj = iterator.next();
          obj != NULL;
          obj = iterator.next()) {
@@ -4917,13 +4917,20 @@
 }


-class FreeListNodesFilter {
+class HeapObjectsFilter {
+ public:
+  virtual ~HeapObjectsFilter() {}
+  virtual bool SkipObject(HeapObject* object) = 0;
+};
+
+
+class FreeListNodesFilter : public HeapObjectsFilter {
  public:
   FreeListNodesFilter() {
     MarkFreeListNodes();
   }

-  inline bool IsFreeListNode(HeapObject* object) {
+  bool SkipObject(HeapObject* object) {
     if (object->IsMarked()) {
       object->ClearMark();
       return true;
@@ -4950,6 +4957,65 @@
       if (FreeListNode::IsFreeListNode(obj)) obj->SetMark();
     }
   }
+
+  AssertNoAllocation no_alloc;
+};
+
+
+class UnreachableObjectsFilter : public HeapObjectsFilter {
+ public:
+  UnreachableObjectsFilter() {
+    MarkUnreachableObjects();
+  }
+
+  bool SkipObject(HeapObject* object) {
+    if (object->IsMarked()) {
+      object->ClearMark();
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+ private:
+  class UnmarkingVisitor : public ObjectVisitor {
+   public:
+    UnmarkingVisitor() : list_(10) {}
+
+    void VisitPointers(Object** start, Object** end) {
+      for (Object** p = start; p < end; p++) {
+        if (!(*p)->IsHeapObject()) continue;
+        HeapObject* obj = HeapObject::cast(*p);
+        if (obj->IsMarked()) {
+          obj->ClearMark();
+          list_.Add(obj);
+        }
+      }
+    }
+
+    bool can_process() { return !list_.is_empty(); }
+
+    void ProcessNext() {
+      HeapObject* obj = list_.RemoveLast();
+      obj->Iterate(this);
+    }
+
+   private:
+    List<HeapObject*> list_;
+  };
+
+  void MarkUnreachableObjects() {
+    HeapIterator iterator;
+    for (HeapObject* obj = iterator.next();
+         obj != NULL;
+         obj = iterator.next()) {
+      obj->SetMark();
+    }
+    UnmarkingVisitor visitor;
+    Heap::IterateRoots(&visitor, VISIT_ONLY_STRONG);
+    while (visitor.can_process())
+      visitor.ProcessNext();
+  }

   AssertNoAllocation no_alloc;
 };
@@ -4962,7 +5028,7 @@
 }


-HeapIterator::HeapIterator(HeapIterator::FreeListNodesFiltering filtering)
+HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering)
     : filtering_(filtering),
       filter_(NULL) {
   Init();
@@ -4976,12 +5042,17 @@

 void HeapIterator::Init() {
   // Start the iteration.
-  if (filtering_ == kPreciseFiltering) {
-    filter_ = new FreeListNodesFilter;
-    space_iterator_ =
-        new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject);
-  } else {
-    space_iterator_ = new SpaceIterator;
+  space_iterator_ = filtering_ == kNoFiltering ? new SpaceIterator :
+      new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject);
+  switch (filtering_) {
+    case kFilterFreeListNodes:
+      filter_ = new FreeListNodesFilter;
+      break;
+    case kFilterUnreachable:
+      filter_ = new UnreachableObjectsFilter;
+      break;
+    default:
+      break;
   }
   object_iterator_ = space_iterator_->next();
 }
@@ -4989,9 +5060,9 @@

 void HeapIterator::Shutdown() {
 #ifdef DEBUG
-  // Assert that in precise mode we have iterated through all
+  // Assert that in filtering mode we have iterated through all
   // objects. Otherwise, heap will be left in an inconsistent state.
-  if (filtering_ == kPreciseFiltering) {
+  if (filtering_ != kNoFiltering) {
     ASSERT(object_iterator_ == NULL);
   }
 #endif
@@ -5008,7 +5079,7 @@
   if (filter_ == NULL) return NextObject();

   HeapObject* obj = NextObject();
-  while (obj != NULL && filter_->IsFreeListNode(obj)) obj = NextObject();
+  while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject();
   return obj;
 }

=======================================
--- /branches/bleeding_edge/src/heap.h  Mon Dec 20 05:52:14 2010
+++ /branches/bleeding_edge/src/heap.h  Tue Dec 21 02:49:40 2010
@@ -1585,17 +1585,18 @@
 // nodes filtering uses GC marks, it can't be used during MS/MC GC
 // phases. Also, it is forbidden to interrupt iteration in this mode,
 // as this will leave heap objects marked (and thus, unusable).
-class FreeListNodesFilter;
+class HeapObjectsFilter;

 class HeapIterator BASE_EMBEDDED {
  public:
-  enum FreeListNodesFiltering {
+  enum HeapObjectsFiltering {
     kNoFiltering,
-    kPreciseFiltering
+    kFilterFreeListNodes,
+    kFilterUnreachable
   };

   HeapIterator();
-  explicit HeapIterator(FreeListNodesFiltering filtering);
+  explicit HeapIterator(HeapObjectsFiltering filtering);
   ~HeapIterator();

   HeapObject* next();
@@ -1608,8 +1609,8 @@
   void Shutdown();
   HeapObject* NextObject();

-  FreeListNodesFiltering filtering_;
-  FreeListNodesFilter* filter_;
+  HeapObjectsFiltering filtering_;
+  HeapObjectsFilter* filter_;
   // Space iterator for iterating all the spaces.
   SpaceIterator* space_iterator_;
   // Object iterator for the space currently being iterated.
=======================================
--- /branches/bleeding_edge/src/profile-generator.cc Mon Dec 13 02:42:06 2010 +++ /branches/bleeding_edge/src/profile-generator.cc Tue Dec 21 02:49:40 2010
@@ -2218,7 +2218,7 @@
 void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
   if (control_ == NULL) return;

-  HeapIterator iterator(HeapIterator::kPreciseFiltering);
+  HeapIterator iterator(HeapIterator::kFilterUnreachable);
   int objects_count = 0;
   for (HeapObject* obj = iterator.next();
        obj != NULL;
@@ -2342,8 +2342,6 @@
     ASSERT(dominators[i] != NULL);
     ordered_entries[i]->set_dominator(dominators[i]);
   }
-  // For nodes unreachable from root, set dominator to itself.
-  snapshot_->SetDominatorsToSelf();
   return true;
 }

@@ -2373,9 +2371,9 @@


 bool HeapSnapshotGenerator::IterateAndExtractReferences() {
-  HeapIterator iterator(HeapIterator::kPreciseFiltering);
+  HeapIterator iterator(HeapIterator::kFilterUnreachable);
   bool interrupted = false;
-  // Heap iteration with precise filtering must be finished in any case.
+  // Heap iteration with filtering must be finished in any case.
   for (HeapObject* obj = iterator.next();
        obj != NULL;
        obj = iterator.next(), IncProgressCounter()) {
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap.cc Tue Dec 7 03:31:57 2010 +++ /branches/bleeding_edge/test/cctest/test-heap.cc Tue Dec 21 02:49:40 2010
@@ -1216,7 +1216,7 @@
 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
   InitializeVM();
   intptr_t size_of_objects_1 = Heap::SizeOfObjects();
-  HeapIterator iterator(HeapIterator::kPreciseFiltering);
+  HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
   intptr_t size_of_objects_2 = 0;
   for (HeapObject* obj = iterator.next();
        obj != NULL;
@@ -1240,3 +1240,65 @@
     CHECK_GT(size_of_objects_2 / 100, delta);
   }
 }
+
+
+class HeapIteratorTestHelper {
+ public:
+  HeapIteratorTestHelper(Object* a, Object* b)
+      : a_(a), b_(b), a_found_(false), b_found_(false) {}
+  bool a_found() { return a_found_; }
+  bool b_found() { return b_found_; }
+  void IterateHeap(HeapIterator::HeapObjectsFiltering mode) {
+    HeapIterator iterator(mode);
+    for (HeapObject* obj = iterator.next();
+         obj != NULL;
+         obj = iterator.next()) {
+      if (obj == a_)
+        a_found_ = true;
+      else if (obj == b_)
+        b_found_ = true;
+    }
+  }
+ private:
+  Object* a_;
+  Object* b_;
+  bool a_found_;
+  bool b_found_;
+};
+
+TEST(HeapIteratorFilterUnreachable) {
+  InitializeVM();
+  v8::HandleScope scope;
+  CompileRun("a = {}; b = {};");
+  v8::Handle<Object> a(Top::context()->global()->GetProperty(
+      *Factory::LookupAsciiSymbol("a"))->ToObjectChecked());
+  v8::Handle<Object> b(Top::context()->global()->GetProperty(
+      *Factory::LookupAsciiSymbol("b"))->ToObjectChecked());
+  CHECK_NE(*a, *b);
+  {
+    HeapIteratorTestHelper helper(*a, *b);
+    helper.IterateHeap(HeapIterator::kFilterUnreachable);
+    CHECK(helper.a_found());
+    CHECK(helper.b_found());
+  }
+  CHECK(Top::context()->global()->DeleteProperty(
+      *Factory::LookupAsciiSymbol("a"), JSObject::FORCE_DELETION));
+  // We ensure that GC will not happen, so our raw pointer stays valid.
+  AssertNoAllocation no_alloc;
+  Object* a_saved = *a;
+  a.Clear();
+  // Verify that "a" object still resides in the heap...
+  {
+    HeapIteratorTestHelper helper(a_saved, *b);
+    helper.IterateHeap(HeapIterator::kNoFiltering);
+    CHECK(helper.a_found());
+    CHECK(helper.b_found());
+  }
+  // ...but is now unreachable.
+  {
+    HeapIteratorTestHelper helper(a_saved, *b);
+    helper.IterateHeap(HeapIterator::kFilterUnreachable);
+    CHECK(!helper.a_found());
+    CHECK(helper.b_found());
+  }
+}

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to