Index: src/heap.cc |
=================================================================== |
--- src/heap.cc (revision 1910) |
+++ src/heap.cc (working copy) |
@@ -538,7 +538,7 @@ |
// Shared state read by the scavenge collector and set by ScavengeObject. |
-static Address promoted_rear = NULL; |
+static Address promoted_top = NULL; |
#ifdef DEBUG |
@@ -554,36 +554,26 @@ |
} |
} |
}; |
+#endif |
- |
-static void VerifyNonPointerSpacePointers() { |
- // Verify that there are no pointers to new space in spaces where we |
- // do not expect them. |
- VerifyNonPointerSpacePointersVisitor v; |
- HeapObjectIterator code_it(Heap::code_space()); |
- while (code_it.has_next()) { |
- HeapObject* object = code_it.next(); |
- if (object->IsCode()) { |
- Code::cast(object)->ConvertICTargetsFromAddressToObject(); |
+void Heap::Scavenge() { |
+#ifdef DEBUG |
+ if (FLAG_enable_slow_asserts) { |
+ VerifyNonPointerSpacePointersVisitor v; |
+ HeapObjectIterator it(code_space_); |
+ while (it.has_next()) { |
+ HeapObject* object = it.next(); |
+ if (object->IsCode()) { |
+ Code::cast(object)->ConvertICTargetsFromAddressToObject(); |
+ } |
object->Iterate(&v); |
- Code::cast(object)->ConvertICTargetsFromObjectToAddress(); |
- } else { |
- // If we find non-code objects in code space (e.g., free list |
- // nodes) we want to verify them as well. |
- object->Iterate(&v); |
+ if (object->IsCode()) { |
+ Code::cast(object)->ConvertICTargetsFromObjectToAddress(); |
+ } |
} |
} |
- |
- HeapObjectIterator data_it(Heap::old_data_space()); |
- while (data_it.has_next()) data_it.next()->Iterate(&v); |
-} |
#endif |
-void Heap::Scavenge() { |
-#ifdef DEBUG |
- if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers(); |
-#endif |
- |
gc_state_ = SCAVENGE; |
// Implements Cheney's copying algorithm |
@@ -606,70 +596,72 @@ |
new_space_.Flip(); |
new_space_.ResetAllocationInfo(); |
- // We need to sweep newly copied objects which can be either in the |
- // to space or promoted to the old generation. For to-space |
- // objects, we treat the bottom of the to space as a queue. Newly |
- // copied and unswept objects lie between a 'front' mark and the |
- // allocation pointer. |
+ // We need to sweep newly copied objects which can be in either the to space |
+ // or the old space. For to space objects, we use a mark. Newly copied |
+ // objects lie between the mark and the allocation top. For objects |
+ // promoted to old space, we write their addresses downward from the top of |
+ // the new space. Sweeping newly promoted objects requires an allocation |
+ // pointer and a mark. Note that the allocation pointer 'top' actually |
+ // moves downward from the high address in the to space. |
// |
- // Promoted objects can go into various old-generation spaces, and |
- // can be allocated internally in the spaces (from the free list). |
- // We treat the top of the to space as a queue of addresses of |
- // promoted objects. The addresses of newly promoted and unswept |
- // objects lie between a 'front' mark and a 'rear' mark that is |
- // updated as a side effect of promoting an object. |
- // |
- // There is guaranteed to be enough room at the top of the to space |
- // for the addresses of promoted objects: every object promoted |
- // frees up its size in bytes from the top of the new space, and |
- // objects are at least one pointer in size. |
- Address new_space_front = new_space_.ToSpaceLow(); |
- Address promoted_front = new_space_.ToSpaceHigh(); |
- promoted_rear = new_space_.ToSpaceHigh(); |
+ // There is guaranteed to be enough room at the top of the to space for the |
+ // addresses of promoted objects: every object promoted frees up its size in |
+ // bytes from the top of the new space, and objects are at least one pointer |
+ // in size. Using the new space to record promoted addresses makes the |
+ // scavenge collector agnostic to the allocation strategy (eg, linear or |
+ // free-list) used in old space. |
+ Address new_mark = new_space_.ToSpaceLow(); |
+ Address promoted_mark = new_space_.ToSpaceHigh(); |
+ promoted_top = new_space_.ToSpaceHigh(); |
ScavengeVisitor scavenge_visitor; |
// Copy roots. |
IterateRoots(&scavenge_visitor); |
- // Copy objects reachable from weak pointers. |
- GlobalHandles::IterateWeakRoots(&scavenge_visitor); |
- |
- // Copy objects reachable from the old generation. By definition, |
- // there are no intergenerational pointers in code or data spaces. |
+ // Copy objects reachable from the old generation. By definition, there |
+ // are no intergenerational pointers in code or data spaces. |
IterateRSet(old_pointer_space_, &ScavengePointer); |
IterateRSet(map_space_, &ScavengePointer); |
lo_space_->IterateRSet(&ScavengePointer); |
- do { |
- ASSERT(new_space_front <= new_space_.top()); |
- ASSERT(promoted_front >= promoted_rear); |
+ bool has_processed_weak_pointers = false; |
- // The addresses new_space_front and new_space_.top() define a |
- // queue of unprocessed copied objects. Process them until the |
- // queue is empty. |
- while (new_space_front < new_space_.top()) { |
- HeapObject* object = HeapObject::FromAddress(new_space_front); |
- object->Iterate(&scavenge_visitor); |
- new_space_front += object->Size(); |
- } |
+ while (true) { |
+ ASSERT(new_mark <= new_space_.top()); |
+ ASSERT(promoted_mark >= promoted_top); |
- // The addresses promoted_front and promoted_rear define a queue |
- // of unprocessed addresses of promoted objects. Process them |
- // until the queue is empty. |
- while (promoted_front > promoted_rear) { |
- promoted_front -= kPointerSize; |
- HeapObject* object = |
- HeapObject::cast(Memory::Object_at(promoted_front)); |
- object->Iterate(&scavenge_visitor); |
- UpdateRSet(object); |
+ // Copy objects reachable from newly copied objects. |
+ while (new_mark < new_space_.top() || promoted_mark > promoted_top) { |
+ // Sweep newly copied objects in the to space. The allocation pointer |
+ // can change during sweeping. |
+ Address previous_top = new_space_.top(); |
+ SemiSpaceIterator new_it(new_space(), new_mark); |
+ while (new_it.has_next()) { |
+ new_it.next()->Iterate(&scavenge_visitor); |
+ } |
+ new_mark = previous_top; |
+ |
+ // Sweep newly copied objects in the old space. The promotion 'top' |
+ // pointer could change during sweeping. |
+ previous_top = promoted_top; |
+ for (Address current = promoted_mark - kPointerSize; |
+ current >= previous_top; |
+ current -= kPointerSize) { |
+ HeapObject* object = HeapObject::cast(Memory::Object_at(current)); |
+ object->Iterate(&scavenge_visitor); |
+ UpdateRSet(object); |
+ } |
+ promoted_mark = previous_top; |
} |
- // Take another spin if there are now unswept objects in new space |
- // (there are currently no more unswept promoted objects). |
- } while (new_space_front < new_space_.top()); |
+ if (has_processed_weak_pointers) break; // We are done. |
+ // Copy objects reachable from weak pointers. |
+ GlobalHandles::IterateWeakRoots(&scavenge_visitor); |
+ has_processed_weak_pointers = true; |
+ } |
// Set age mark. |
- new_space_.set_age_mark(new_space_.top()); |
+ new_space_.set_age_mark(new_mark); |
LOG(ResourceEvent("scavenge", "end")); |
@@ -890,8 +882,8 @@ |
if (target_space == Heap::old_pointer_space_) { |
// Record the object's address at the top of the to space, to allow |
// it to be swept by the scavenger. |
- promoted_rear -= kPointerSize; |
- Memory::Object_at(promoted_rear) = *p; |
+ promoted_top -= kPointerSize; |
+ Memory::Object_at(promoted_top) = *p; |
} else { |
#ifdef DEBUG |
// Objects promoted to the data space should not have pointers to |