Index: src/heap.cc |
=================================================================== |
--- src/heap.cc (revision 1972) |
+++ src/heap.cc (working copy) |
@@ -537,8 +537,39 @@ |
}; |
+// A queue of pointers and maps of to-be-promoted objects during a |
+// scavenge collection. |
+class PromotionQueue { |
+ public: |
+ void Initialize(Address start_address) { |
+ front_ = rear_ = reinterpret_cast<HeapObject**>(start_address); |
+ } |
+ |
+ bool is_empty() { return front_ <= rear_; } |
+ |
+ void insert(HeapObject* object, Map* map) { |
+ *(--rear_) = object; |
+ *(--rear_) = map; |
+ // Assert no overflow into live objects. |
+ ASSERT(reinterpret_cast<Address>(rear_) >= Heap::new_space()->top()); |
+ } |
+ |
+ void remove(HeapObject** object, Map** map) { |
+ *object = *(--front_); |
+ *map = Map::cast(*(--front_)); |
+ // Assert no underflow. |
+ ASSERT(front_ >= rear_); |
+ } |
+ |
+ private: |
+ // The front of the queue is higher in memory than the rear. |
+ HeapObject** front_; |
+ HeapObject** rear_; |
+}; |
+ |
+ |
// Shared state read by the scavenge collector and set by ScavengeObject. |
-static Address promoted_rear = NULL; |
+static PromotionQueue promotion_queue; |
#ifdef DEBUG |
@@ -624,8 +655,7 @@ |
// 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(); |
+ promotion_queue.Initialize(new_space_.ToSpaceHigh()); |
ScavengeVisitor scavenge_visitor; |
// Copy roots. |
@@ -642,7 +672,6 @@ |
do { |
ASSERT(new_space_front <= new_space_.top()); |
- ASSERT(promoted_front >= promoted_rear); |
// The addresses new_space_front and new_space_.top() define a |
// queue of unprocessed copied objects. Process them until the |
@@ -653,15 +682,26 @@ |
new_space_front += object->Size(); |
} |
- // 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); |
+ // Promote and process all the to-be-promoted objects. |
+ while (!promotion_queue.is_empty()) { |
+ HeapObject* source; |
+ Map* map; |
+ promotion_queue.remove(&source, &map); |
+ // Copy the from-space object to its new location (given by the |
+ // forwarding address) and fix its map. |
+ HeapObject* target = source->map_word().ToForwardingAddress(); |
+ CopyBlock(reinterpret_cast<Object**>(target->address()), |
+ reinterpret_cast<Object**>(source->address()), |
+ source->SizeFromMap(map)); |
+ target->set_map(map); |
+ |
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
+ // Update NewSpace stats if necessary. |
+ RecordCopiedObject(target); |
+#endif |
+ // Visit the newly copied object for pointers to new space. |
+ target->Iterate(&scavenge_visitor); |
+ UpdateRSet(target); |
} |
// Take another spin if there are now unswept objects in new space |
@@ -818,8 +858,8 @@ |
// Set the forwarding address. |
source->set_map_word(MapWord::FromForwardingAddress(target)); |
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
// Update NewSpace stats if necessary. |
-#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
RecordCopiedObject(target); |
#endif |
@@ -827,28 +867,6 @@ |
} |
-// Inlined function. |
-void Heap::ScavengeObject(HeapObject** p, HeapObject* object) { |
- ASSERT(InFromSpace(object)); |
- |
- // We use the first word (where the map pointer usually is) of a heap |
- // object to record the forwarding pointer. A forwarding pointer can |
- // point to an old space, the code space, or the to space of the new |
- // generation. |
- MapWord first_word = object->map_word(); |
- |
- // If the first word is a forwarding address, the object has already been |
- // copied. |
- if (first_word.IsForwardingAddress()) { |
- *p = first_word.ToForwardingAddress(); |
- return; |
- } |
- |
- // Call the slow part of scavenge object. |
- return ScavengeObjectSlow(p, object); |
-} |
- |
- |
static inline bool IsShortcutCandidate(HeapObject* object, Map* map) { |
STATIC_ASSERT(kNotStringTag != 0 && kSymbolTag != 0); |
ASSERT(object->map() == map); |
@@ -879,6 +897,11 @@ |
} |
int object_size = object->SizeFromMap(first_word.ToMap()); |
+ // We rely on live objects in new space to be at least two pointers, |
+ // so we can store the from-space address and map pointer of promoted |
+ // objects in the to space. |
+ ASSERT(object_size >= 2 * kPointerSize); |
+ |
// If the object should be promoted, we try to copy it to old space. |
if (ShouldBePromoted(object->address(), object_size)) { |
OldSpace* target_space = Heap::TargetSpace(object); |
@@ -886,16 +909,29 @@ |
target_space == Heap::old_data_space_); |
Object* result = target_space->AllocateRaw(object_size); |
if (!result->IsFailure()) { |
- *p = MigrateObject(object, HeapObject::cast(result), object_size); |
+ HeapObject* target = HeapObject::cast(result); |
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; |
+ // Save the from-space object pointer and its map pointer at the |
+ // top of the to space to be swept and copied later. Write the |
+ // forwarding address over the map word of the from-space |
+ // object. |
+ promotion_queue.insert(object, first_word.ToMap()); |
+ object->set_map_word(MapWord::FromForwardingAddress(target)); |
+ |
+ // Give the space allocated for the result a proper map by |
+ // treating it as a free list node (not linked into the free |
+ // list). |
+ FreeListNode* node = FreeListNode::FromAddress(target->address()); |
+ node->set_size(object_size); |
+ |
+ *p = target; |
} else { |
+ // Objects promoted to the data space can be copied immediately |
+ // and not revisited---we will never sweep that space for |
+ // pointers and the copied objects do not contain pointers to |
+ // new space objects. |
+ *p = MigrateObject(object, target, object_size); |
#ifdef DEBUG |
- // Objects promoted to the data space should not have pointers to |
- // new space. |
VerifyNonPointerSpacePointersVisitor v; |
(*p)->Iterate(&v); |
#endif |