| 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;
|
|
|