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