Index: src/heap/mark-compact.cc |
diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc |
index e9d5332aa34d8ad2f100aa34bba0f2a74510d575..89c285d699d2941a2fed96379cc408e41bb547f3 100644 |
--- a/src/heap/mark-compact.cc |
+++ b/src/heap/mark-compact.cc |
@@ -33,8 +33,8 @@ namespace internal { |
const char* Marking::kWhiteBitPattern = "00"; |
-const char* Marking::kBlackBitPattern = "10"; |
-const char* Marking::kGreyBitPattern = "11"; |
+const char* Marking::kBlackBitPattern = "11"; |
+const char* Marking::kGreyBitPattern = "10"; |
const char* Marking::kImpossibleBitPattern = "01"; |
@@ -115,6 +115,8 @@ static void VerifyMarking(Heap* heap, Address bottom, Address top) { |
CHECK(current >= next_object_must_be_here_or_later); |
object->Iterate(&visitor); |
next_object_must_be_here_or_later = current + object->Size(); |
+ // The next word for sure belongs to the current object, jump over it. |
+ current += kPointerSize; |
} |
} |
} |
@@ -237,8 +239,8 @@ static void VerifyEvacuation(Heap* heap) { |
void MarkCompactCollector::SetUp() { |
DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); |
- DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0); |
- DCHECK(strcmp(Marking::kGreyBitPattern, "11") == 0); |
+ DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); |
+ DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); |
DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); |
free_list_old_space_.Reset(new FreeList(heap_->old_space())); |
@@ -1525,51 +1527,16 @@ void MarkCompactCollector::DiscoverGreyObjectsWithIterator(T* it) { |
} |
-static inline int MarkWordToObjectStarts(uint32_t mark_bits, |
- uint32_t next_mark_bits, Address base, |
- Address* starts); |
- |
- |
void MarkCompactCollector::DiscoverGreyObjectsOnPage(MemoryChunk* p) { |
DCHECK(!marking_deque()->IsFull()); |
- DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); |
- DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0); |
- DCHECK(strcmp(Marking::kGreyBitPattern, "11") == 0); |
- DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); |
- |
- for (MarkBitCellIterator it(p); !it.Done(); it.Advance()) { |
- Address cell_base = it.CurrentCellBase(); |
- MarkBit::CellType* cell = it.CurrentCell(); |
- |
- const MarkBit::CellType current_cell = *cell; |
- if (current_cell == 0) continue; |
- |
- MarkBit::CellType grey_objects; |
- if (it.HasNext()) { |
- const MarkBit::CellType next_cell = *(cell + 1); |
- grey_objects = current_cell & ((current_cell >> 1) | |
- (next_cell << (Bitmap::kBitsPerCell - 1))); |
- } else { |
- grey_objects = current_cell & (current_cell >> 1); |
- } |
- |
- int offset = 0; |
- while (grey_objects != 0) { |
- int trailing_zeros = base::bits::CountTrailingZeros32(grey_objects); |
- grey_objects >>= trailing_zeros; |
- offset += trailing_zeros; |
- MarkBit markbit(cell, 1 << offset); |
- DCHECK(Marking::IsGrey(markbit)); |
- Marking::GreyToBlack(markbit); |
- Address addr = cell_base + offset * kPointerSize; |
- HeapObject* object = HeapObject::FromAddress(addr); |
- PushBlack(object); |
- if (marking_deque()->IsFull()) return; |
- offset += 2; |
- grey_objects >>= 2; |
- } |
- |
- grey_objects >>= (Bitmap::kBitsPerCell - 1); |
+ LiveObjectIterator<kGreyObjects> it(p); |
+ HeapObject* object = NULL; |
+ while ((object = it.Next()) != NULL) { |
+ MarkBit markbit = Marking::MarkBitFrom(object); |
+ DCHECK(Marking::IsGrey(markbit)); |
+ Marking::GreyToBlack(markbit); |
+ PushBlack(object); |
+ if (marking_deque()->IsFull()) return; |
} |
} |
@@ -2948,68 +2915,77 @@ bool MarkCompactCollector::IsSlotInBlackObject(Page* p, Address slot, |
} |
uint32_t mark_bit_index = p->AddressToMarkbitIndex(slot); |
- unsigned int start_index = mark_bit_index >> Bitmap::kBitsPerCellLog2; |
- MarkBit::CellType index_in_cell = 1U |
- << (mark_bit_index & Bitmap::kBitIndexMask); |
+ unsigned int cell_index = mark_bit_index >> Bitmap::kBitsPerCellLog2; |
+ MarkBit::CellType index_mask = 1u << Bitmap::IndexInCell(mark_bit_index); |
MarkBit::CellType* cells = p->markbits()->cells(); |
- Address cell_base = p->area_start(); |
- unsigned int cell_base_start_index = Bitmap::IndexToCell( |
- Bitmap::CellAlignIndex(p->AddressToMarkbitIndex(cell_base))); |
+ Address base_address = p->area_start(); |
+ unsigned int base_address_cell_index = Bitmap::IndexToCell( |
+ Bitmap::CellAlignIndex(p->AddressToMarkbitIndex(base_address))); |
// Check if the slot points to the start of an object. This can happen e.g. |
// when we left trim a fixed array. Such slots are invalid and we can remove |
// them. |
- if ((cells[start_index] & index_in_cell) != 0) { |
- return false; |
+ if (index_mask > 1) { |
+ if ((cells[cell_index] & index_mask) != 0 && |
+ (cells[cell_index] & (index_mask >> 1)) == 0) { |
+ return false; |
+ } |
+ } else { |
+ // Left trimming moves the mark bits so we cannot be in the very first cell. |
+ DCHECK(cell_index != base_address_cell_index); |
+ if ((cells[cell_index] & index_mask) != 0 && |
+ (cells[cell_index - 1] & (1u << Bitmap::kBitIndexMask)) == 0) { |
+ return false; |
+ } |
} |
// Check if the object is in the current cell. |
MarkBit::CellType slot_mask; |
- if ((cells[start_index] == 0) || |
- (base::bits::CountTrailingZeros32(cells[start_index]) > |
- base::bits::CountTrailingZeros32(cells[start_index] | index_in_cell))) { |
+ if ((cells[cell_index] == 0) || |
+ (base::bits::CountTrailingZeros32(cells[cell_index]) > |
+ base::bits::CountTrailingZeros32(cells[cell_index] | index_mask))) { |
// If we are already in the first cell, there is no live object. |
- if (start_index == cell_base_start_index) return false; |
+ if (cell_index == base_address_cell_index) return false; |
// If not, find a cell in a preceding cell slot that has a mark bit set. |
do { |
- start_index--; |
- } while (start_index > cell_base_start_index && cells[start_index] == 0); |
+ cell_index--; |
+ } while (cell_index > base_address_cell_index && cells[cell_index] == 0); |
// The slot must be in a dead object if there are no preceding cells that |
// have mark bits set. |
- if (cells[start_index] == 0) { |
+ if (cells[cell_index] == 0) { |
return false; |
} |
// The object is in a preceding cell. Set the mask to find any object. |
- slot_mask = 0xffffffff; |
+ slot_mask = ~0u; |
} else { |
- // The object start is before the the slot index. Hence, in this case the |
- // slot index can not be at the beginning of the cell. |
- CHECK(index_in_cell > 1); |
// We are interested in object mark bits right before the slot. |
- slot_mask = index_in_cell - 1; |
+ slot_mask = index_mask + (index_mask - 1); |
} |
- MarkBit::CellType current_cell = cells[start_index]; |
+ MarkBit::CellType current_cell = cells[cell_index]; |
CHECK(current_cell != 0); |
// Find the last live object in the cell. |
unsigned int leading_zeros = |
base::bits::CountLeadingZeros32(current_cell & slot_mask); |
- CHECK(leading_zeros != 32); |
- unsigned int offset = Bitmap::kBitIndexMask - leading_zeros; |
+ CHECK(leading_zeros != Bitmap::kBitsPerCell); |
+ int offset = static_cast<int>(Bitmap::kBitIndexMask - leading_zeros) - 1; |
- cell_base += (start_index - cell_base_start_index) * 32 * kPointerSize; |
- Address address = cell_base + offset * kPointerSize; |
+ base_address += (cell_index - base_address_cell_index) * |
+ Bitmap::kBitsPerCell * kPointerSize; |
+ Address address = base_address + offset * kPointerSize; |
HeapObject* object = HeapObject::FromAddress(address); |
CHECK(Marking::IsBlack(Marking::MarkBitFrom(object))); |
CHECK(object->address() < reinterpret_cast<Address>(slot)); |
- if (object->address() <= slot && |
+ if ((object->address() + kPointerSize) <= slot && |
(object->address() + object->Size()) > slot) { |
// If the slot is within the last found object in the cell, the slot is |
// in a live object. |
+ // Slots pointing to the first word of an object are invalid and removed. |
+ // This can happen when we move the object header while left trimming. |
*out_object = object; |
return true; |
} |
@@ -3020,32 +2996,26 @@ bool MarkCompactCollector::IsSlotInBlackObject(Page* p, Address slot, |
bool MarkCompactCollector::IsSlotInBlackObjectSlow(Page* p, Address slot) { |
// This function does not support large objects right now. |
Space* owner = p->owner(); |
- if (owner == heap_->lo_space() || owner == NULL) return true; |
- |
- for (MarkBitCellIterator it(p); !it.Done(); it.Advance()) { |
- Address cell_base = it.CurrentCellBase(); |
- MarkBit::CellType* cell = it.CurrentCell(); |
- |
- MarkBit::CellType current_cell = *cell; |
- if (current_cell == 0) continue; |
- |
- int offset = 0; |
- while (current_cell != 0) { |
- int trailing_zeros = base::bits::CountTrailingZeros32(current_cell); |
- current_cell >>= trailing_zeros; |
- offset += trailing_zeros; |
- Address address = cell_base + offset * kPointerSize; |
- |
- HeapObject* object = HeapObject::FromAddress(address); |
- int size = object->Size(); |
+ if (owner == heap_->lo_space() || owner == NULL) { |
+ Object* large_object = heap_->lo_space()->FindObject(slot); |
+ // This object has to exist, otherwise we would not have recorded a slot |
+ // for it. |
+ CHECK(large_object->IsHeapObject()); |
+ HeapObject* large_heap_object = HeapObject::cast(large_object); |
+ if (IsMarked(large_heap_object)) { |
+ return true; |
+ } |
+ return false; |
+ } |
- if (object->address() > slot) return false; |
- if (object->address() <= slot && slot < (object->address() + size)) { |
- return true; |
- } |
+ LiveObjectIterator<kBlackObjects> it(p); |
+ HeapObject* object = NULL; |
+ while ((object = it.Next()) != NULL) { |
+ int size = object->Size(); |
- offset++; |
- current_cell >>= 1; |
+ if (object->address() > slot) return false; |
+ if (object->address() <= slot && slot < (object->address() + size)) { |
+ return true; |
} |
} |
return false; |
@@ -3384,7 +3354,6 @@ static int Sweep(PagedSpace* space, FreeList* free_list, Page* p, |
Address free_start = p->area_start(); |
DCHECK(reinterpret_cast<intptr_t>(free_start) % (32 * kPointerSize) == 0); |
- Address starts[16]; |
// If we use the skip list for code space pages, we have to lock the skip |
// list because it could be accessed concurrently by the runtime or the |
@@ -3398,43 +3367,39 @@ static int Sweep(PagedSpace* space, FreeList* free_list, Page* p, |
intptr_t max_freed_bytes = 0; |
int curr_region = -1; |
- for (MarkBitCellIterator it(p); !it.Done(); it.Advance()) { |
- Address cell_base = it.CurrentCellBase(); |
- MarkBit::CellType* cell = it.CurrentCell(); |
- int live_objects = |
- MarkWordToObjectStarts(*cell, it.PeekNext(), cell_base, starts); |
- int live_index = 0; |
- for (; live_objects != 0; live_objects--) { |
- Address free_end = starts[live_index++]; |
- if (free_end != free_start) { |
- int size = static_cast<int>(free_end - free_start); |
- if (free_space_mode == ZAP_FREE_SPACE) { |
- memset(free_start, 0xcc, size); |
- } |
- freed_bytes = Free<parallelism>(space, free_list, free_start, size); |
- max_freed_bytes = Max(freed_bytes, max_freed_bytes); |
- } |
- HeapObject* live_object = HeapObject::FromAddress(free_end); |
- DCHECK(Marking::IsBlack(Marking::MarkBitFrom(live_object))); |
- Map* map = live_object->synchronized_map(); |
- int size = live_object->SizeFromMap(map); |
- if (sweeping_mode == SWEEP_AND_VISIT_LIVE_OBJECTS) { |
- live_object->IterateBody(map->instance_type(), size, v); |
+ LiveObjectIterator<kBlackObjects> it(p); |
+ HeapObject* object = NULL; |
+ while ((object = it.Next()) != NULL) { |
+ DCHECK(Marking::IsBlack(Marking::MarkBitFrom(object))); |
+ Address free_end = object->address(); |
+ if (free_end != free_start) { |
+ int size = static_cast<int>(free_end - free_start); |
+ if (free_space_mode == ZAP_FREE_SPACE) { |
+ memset(free_start, 0xcc, size); |
} |
- if ((skip_list_mode == REBUILD_SKIP_LIST) && skip_list != NULL) { |
- int new_region_start = SkipList::RegionNumber(free_end); |
- int new_region_end = |
- SkipList::RegionNumber(free_end + size - kPointerSize); |
- if (new_region_start != curr_region || new_region_end != curr_region) { |
- skip_list->AddObject(free_end, size); |
- curr_region = new_region_end; |
- } |
+ freed_bytes = Free<parallelism>(space, free_list, free_start, size); |
+ max_freed_bytes = Max(freed_bytes, max_freed_bytes); |
+ } |
+ Map* map = object->synchronized_map(); |
+ int size = object->SizeFromMap(map); |
+ if (sweeping_mode == SWEEP_AND_VISIT_LIVE_OBJECTS) { |
+ object->IterateBody(map->instance_type(), size, v); |
+ } |
+ if ((skip_list_mode == REBUILD_SKIP_LIST) && skip_list != NULL) { |
+ int new_region_start = SkipList::RegionNumber(free_end); |
+ int new_region_end = |
+ SkipList::RegionNumber(free_end + size - kPointerSize); |
+ if (new_region_start != curr_region || new_region_end != curr_region) { |
+ skip_list->AddObject(free_end, size); |
+ curr_region = new_region_end; |
} |
- free_start = free_end + size; |
} |
- // Clear marking bits for current cell. |
- *cell = 0; |
+ free_start = free_end + size; |
} |
+ |
+ // Clear the mark bits of that page and reset live bytes count. |
+ Bitmap::Clear(p); |
+ |
if (free_start != p->area_end()) { |
int size = static_cast<int>(p->area_end() - free_start); |
if (free_space_mode == ZAP_FREE_SPACE) { |
@@ -3443,7 +3408,6 @@ static int Sweep(PagedSpace* space, FreeList* free_list, Page* p, |
freed_bytes = Free<parallelism>(space, free_list, free_start, size); |
max_freed_bytes = Max(freed_bytes, max_freed_bytes); |
} |
- p->ResetLiveBytes(); |
if (parallelism == MarkCompactCollector::SWEEP_IN_PARALLEL) { |
// When concurrent sweeping is active, the page will be marked after |
@@ -3496,32 +3460,38 @@ void MarkCompactCollector::RemoveObjectSlots(Address start_slot, |
} |
} |
+#ifdef VERIFY_HEAP |
+static void VerifyAllBlackObjects(MemoryChunk* page) { |
+ LiveObjectIterator<kAllLiveObjects> it(page); |
+ HeapObject* object = NULL; |
+ while ((object = it.Next()) != NULL) { |
+ CHECK(Marking::IsBlack(Marking::MarkBitFrom(object))); |
+ } |
+} |
+#endif // VERIFY_HEAP |
bool MarkCompactCollector::VisitLiveObjects(MemoryChunk* page, |
HeapObjectVisitor* visitor, |
IterationMode mode) { |
- Address offsets[16]; |
- for (MarkBitCellIterator it(page); !it.Done(); it.Advance()) { |
- Address cell_base = it.CurrentCellBase(); |
- MarkBit::CellType* cell = it.CurrentCell(); |
- if (*cell == 0) continue; |
- int live_objects = |
- MarkWordToObjectStarts(*cell, it.PeekNext(), cell_base, offsets); |
- for (int i = 0; i < live_objects; i++) { |
- HeapObject* object = HeapObject::FromAddress(offsets[i]); |
- DCHECK(Marking::IsBlack(Marking::MarkBitFrom(object))); |
- if (!visitor->Visit(object)) { |
- if ((mode == kClearMarkbits) && (i > 0)) { |
- page->markbits()->ClearRange( |
- page->AddressToMarkbitIndex(page->area_start()), |
- page->AddressToMarkbitIndex(offsets[i])); |
- } |
- return false; |
+#ifdef VERIFY_HEAP |
+ VerifyAllBlackObjects(page); |
+#endif // VERIFY_HEAP |
+ |
+ LiveObjectIterator<kBlackObjects> it(page); |
+ HeapObject* object = NULL; |
+ while ((object = it.Next()) != NULL) { |
+ DCHECK(Marking::IsBlack(Marking::MarkBitFrom(object))); |
+ if (!visitor->Visit(object)) { |
+ if (mode == kClearMarkbits) { |
+ page->markbits()->ClearRange( |
+ page->AddressToMarkbitIndex(page->area_start()), |
+ page->AddressToMarkbitIndex(object->address())); |
} |
+ return false; |
} |
- if (mode == kClearMarkbits) { |
- *cell = 0; |
- } |
+ } |
+ if (mode == kClearMarkbits) { |
+ Bitmap::Clear(page); |
} |
return true; |
} |
@@ -3529,20 +3499,17 @@ bool MarkCompactCollector::VisitLiveObjects(MemoryChunk* page, |
void MarkCompactCollector::VisitLiveObjectsBody(Page* page, |
ObjectVisitor* visitor) { |
- Address starts[16]; |
- for (MarkBitCellIterator it(page); !it.Done(); it.Advance()) { |
- Address cell_base = it.CurrentCellBase(); |
- MarkBit::CellType* cell = it.CurrentCell(); |
- if (*cell == 0) continue; |
- int live_objects = |
- MarkWordToObjectStarts(*cell, it.PeekNext(), cell_base, starts); |
- for (int i = 0; i < live_objects; i++) { |
- HeapObject* live_object = HeapObject::FromAddress(starts[i]); |
- DCHECK(Marking::IsBlack(Marking::MarkBitFrom(live_object))); |
- Map* map = live_object->synchronized_map(); |
- int size = live_object->SizeFromMap(map); |
- live_object->IterateBody(map->instance_type(), size, visitor); |
- } |
+#ifdef VERIFY_HEAP |
+ VerifyAllBlackObjects(page); |
+#endif // VERIFY_HEAP |
+ |
+ LiveObjectIterator<kBlackObjects> it(page); |
+ HeapObject* object = NULL; |
+ while ((object = it.Next()) != NULL) { |
+ DCHECK(Marking::IsBlack(Marking::MarkBitFrom(object))); |
+ Map* map = object->synchronized_map(); |
+ int size = object->SizeFromMap(map); |
+ object->IterateBody(map->instance_type(), size, visitor); |
} |
} |
@@ -3779,47 +3746,6 @@ void MarkCompactCollector::ReleaseEvacuationCandidates() { |
} |
-#ifdef VERIFY_HEAP |
-static bool VerifyAllBlackObjects(uint32_t mark_bits, uint32_t next_mark_bits) { |
- // Check for overlapping mark bits. |
- if ((mark_bits & 0x80000000) && (next_mark_bits & 0x1)) return false; |
- |
- unsigned index = 0; |
- while ((index = base::bits::CountTrailingZeros32(mark_bits)) != 32) { |
- if (index > 0) mark_bits >>= index; |
- if ((mark_bits & 0x3) == 0x3) { |
- // There should not be any grey (11) objects. |
- return false; |
- } |
- mark_bits &= 0xFFFFFFFE; |
- } |
- return true; |
-} |
-#endif // VERIFY_HEAP |
- |
- |
-// Takes a word of mark bits and a base address. Returns the number of objects |
-// that start in the range. Puts the object starts in the supplied array. |
-static inline int MarkWordToObjectStarts(uint32_t mark_bits, |
- uint32_t next_mark_bits, Address base, |
- Address* starts) { |
- int objects = 0; |
- |
-#ifdef VERIFY_HEAP |
- if (FLAG_verify_heap) { |
- CHECK(VerifyAllBlackObjects(mark_bits, next_mark_bits)); |
- } |
-#endif // VERIFY_HEAP |
- |
- unsigned index = 0; |
- while ((index = base::bits::CountTrailingZeros32(mark_bits)) != 32) { |
- starts[objects++] = base + kPointerSize * index; |
- mark_bits &= ~(1u << index); |
- } |
- return objects; |
-} |
- |
- |
int MarkCompactCollector::SweepInParallel(PagedSpace* space, |
int required_freed_bytes) { |
int max_freed = 0; |