Index: src/mark-compact.cc |
=================================================================== |
--- src/mark-compact.cc (revision 7102) |
+++ src/mark-compact.cc (working copy) |
@@ -1,4 +1,4 @@ |
-// Copyright 2006-2008 the V8 project authors. All rights reserved. |
+// Copyright 2011 the V8 project authors. All rights reserved. |
// Redistribution and use in source and binary forms, with or without |
// modification, are permitted provided that the following conditions are |
// met: |
@@ -45,6 +45,7 @@ |
// MarkCompactCollector |
bool MarkCompactCollector::force_compaction_ = false; |
+bool MarkCompactCollector::sweep_precisely_ = false; |
bool MarkCompactCollector::compacting_collection_ = false; |
bool MarkCompactCollector::compact_on_next_gc_ = false; |
@@ -191,7 +192,7 @@ |
#ifdef DEBUG |
static void VerifyMarkbitsAreClean(PagedSpace* space) { |
- PageIterator it(space, PageIterator::PAGES_IN_USE); |
+ PageIterator it(space); |
while (it.has_next()) { |
Page* p = it.next(); |
@@ -210,7 +211,7 @@ |
static void ClearMarkbits(PagedSpace* space) { |
- PageIterator it(space, PageIterator::PAGES_IN_USE); |
+ PageIterator it(space); |
while (it.has_next()) { |
Page* p = it.next(); |
@@ -218,8 +219,11 @@ |
} |
} |
+ |
static void ClearMarkbits() { |
- // We are sweeping code and map spaces precisely so clearing is not required. |
+ // TODO(gc): Clean the mark bits while sweeping. |
+ ClearMarkbits(Heap::code_space()); |
+ ClearMarkbits(Heap::map_space()); |
ClearMarkbits(Heap::old_pointer_space()); |
ClearMarkbits(Heap::old_data_space()); |
ClearMarkbits(Heap::cell_space()); |
@@ -237,9 +241,7 @@ |
// on top of it to see whether they are equal to old_start. |
} |
} else { |
- if (Heap::InNewSpace(old_start) || |
- Page::FromAddress(old_start)->IsFlagSet(Page::IS_CONTINUOUS) || |
- !IsMarked(old_start)) { |
+ if (Heap::InNewSpace(old_start) || !IsMarked(old_start)) { |
return; |
} |
SetMark(new_start); |
@@ -342,7 +344,7 @@ |
OldSpaces spaces; |
for (OldSpace* space = spaces.next(); space != NULL; space = spaces.next()) { |
- old_gen_recoverable += space->Waste() + space->AvailableFree(); |
+ old_gen_recoverable += space->Waste() + space->Available(); |
old_gen_used += space->Size(); |
} |
@@ -1243,8 +1245,8 @@ |
void MarkCompactCollector::CreateBackPointers() { |
HeapObjectIterator iterator(Heap::map_space()); |
- for (HeapObject* next_object = iterator.next(); |
- next_object != NULL; next_object = iterator.next()) { |
+ for (HeapObject* next_object = iterator.Next(); |
+ next_object != NULL; next_object = iterator.Next()) { |
if (next_object->IsMap()) { // Could also be ByteArray on free list. |
Map* map = Map::cast(next_object); |
if (map->instance_type() >= FIRST_JS_OBJECT_TYPE && |
@@ -1564,8 +1566,8 @@ |
// scan the descriptor arrays of those maps, not all maps. |
// All of these actions are carried out only on maps of JSObjects |
// and related subtypes. |
- for (HeapObject* obj = map_iterator.next(); |
- obj != NULL; obj = map_iterator.next()) { |
+ for (HeapObject* obj = map_iterator.Next(); |
+ obj != NULL; obj = map_iterator.Next()) { |
Map* map = reinterpret_cast<Map*>(obj); |
if (!Marking::IsMarked(map) && map->IsByteArray()) continue; |
@@ -1830,9 +1832,9 @@ |
// Update pointers from cells. |
HeapObjectIterator cell_iterator(Heap::cell_space()); |
- for (HeapObject* cell = cell_iterator.next(); |
+ for (HeapObject* cell = cell_iterator.Next(); |
cell != NULL; |
- cell = cell_iterator.next()) { |
+ cell = cell_iterator.Next()) { |
if (cell->IsJSGlobalPropertyCell()) { |
Address value_address = |
reinterpret_cast<Address>(cell) + |
@@ -1877,9 +1879,8 @@ |
} |
uint32_t free_end = Page::MarkbitsBitmap::CellToIndex(free_cell_index); |
- space->DeallocateBlock(p->MarkbitIndexToAddress(free_start), |
- (free_end - free_start) << kPointerSizeLog2, |
- true); |
+ space->Free(p->MarkbitIndexToAddress(free_start), |
+ (free_end - free_start) << kPointerSizeLog2); |
return free_cell_index; |
} |
@@ -1922,109 +1923,414 @@ |
} |
+static const int kStartTableStride = 5; |
+static const int kStartTableSize = 171; |
+static const int kStartTableInvalidEntry = 127; |
+static const int kStartTableUnusedEntry = 126; |
+ |
+#define _ kStartTableUnusedEntry |
+#define X kStartTableInvalidEntry |
+// Mark-bit to object start offset. Since objects are at least 2 words |
+// large we don't have entries for two consecutive 1 bits. All entries |
+// after 170 have at least 2 consecutive bits. |
+char kStartTable[kStartTableSize * kStartTableStride] = { |
Vyacheslav Egorov (Chromium)
2011/03/15 09:20:09
Stride and Size are really mysterious names --- mo
Erik Corry
2011/03/17 13:39:17
Done.
|
+ 0, _, _, _, _, // 0 |
+ 1, 0, _, _, _, // 1 |
+ 1, 1, _, _, _, // 2 |
+ X, _, _, _, _, // 3 |
+ 1, 2, _, _, _, // 4 |
+ 2, 0, 2, _, _, // 5 |
+ X, _, _, _, _, // 6 |
+ X, _, _, _, _, // 7 |
+ 1, 3, _, _, _, // 8 |
+ 2, 0, 3, _, _, // 9 |
+ 2, 1, 3, _, _, // 10 |
+ X, _, _, _, _, // 11 |
+ X, _, _, _, _, // 12 |
+ X, _, _, _, _, // 13 |
+ X, _, _, _, _, // 14 |
+ X, _, _, _, _, // 15 |
+ 1, 4, _, _, _, // 16 |
+ 2, 0, 4, _, _, // 17 |
+ 2, 1, 4, _, _, // 18 |
+ X, _, _, _, _, // 19 |
+ 2, 2, 4, _, _, // 20 |
+ 3, 0, 2, 4, _, // 21 |
+ X, _, _, _, _, // 22 |
+ X, _, _, _, _, // 23 |
+ X, _, _, _, _, // 24 |
+ X, _, _, _, _, // 25 |
+ X, _, _, _, _, // 26 |
+ X, _, _, _, _, // 27 |
+ X, _, _, _, _, // 28 |
+ X, _, _, _, _, // 29 |
+ X, _, _, _, _, // 30 |
+ X, _, _, _, _, // 31 |
+ 1, 5, _, _, _, // 32 |
+ 2, 0, 5, _, _, // 33 |
+ 2, 1, 5, _, _, // 34 |
+ X, _, _, _, _, // 35 |
+ 2, 2, 5, _, _, // 36 |
+ 3, 0, 2, 5, _, // 37 |
+ X, _, _, _, _, // 38 |
+ X, _, _, _, _, // 39 |
+ 2, 3, 5, _, _, // 40 |
+ 3, 0, 3, 5, _, // 41 |
+ 3, 1, 3, 5, _, // 42 |
+ X, _, _, _, _, // 43 |
+ X, _, _, _, _, // 44 |
+ X, _, _, _, _, // 45 |
+ X, _, _, _, _, // 46 |
+ X, _, _, _, _, // 47 |
+ X, _, _, _, _, // 48 |
+ X, _, _, _, _, // 49 |
+ X, _, _, _, _, // 50 |
+ X, _, _, _, _, // 51 |
+ X, _, _, _, _, // 52 |
+ X, _, _, _, _, // 53 |
+ X, _, _, _, _, // 54 |
+ X, _, _, _, _, // 55 |
+ X, _, _, _, _, // 56 |
+ X, _, _, _, _, // 57 |
+ X, _, _, _, _, // 58 |
+ X, _, _, _, _, // 59 |
+ X, _, _, _, _, // 60 |
+ X, _, _, _, _, // 61 |
+ X, _, _, _, _, // 62 |
+ X, _, _, _, _, // 63 |
+ 1, 6, _, _, _, // 64 |
+ 2, 0, 6, _, _, // 65 |
+ 2, 1, 6, _, _, // 66 |
+ X, _, _, _, _, // 67 |
+ 2, 2, 6, _, _, // 68 |
+ 3, 0, 2, 6, _, // 69 |
+ X, _, _, _, _, // 70 |
+ X, _, _, _, _, // 71 |
+ 2, 3, 6, _, _, // 72 |
+ 3, 0, 3, 6, _, // 73 |
+ 3, 1, 3, 6, _, // 74 |
+ X, _, _, _, _, // 75 |
+ X, _, _, _, _, // 76 |
+ X, _, _, _, _, // 77 |
+ X, _, _, _, _, // 78 |
+ X, _, _, _, _, // 79 |
+ 2, 4, 6, _, _, // 80 |
+ 3, 0, 4, 6, _, // 81 |
+ 3, 1, 4, 6, _, // 82 |
+ X, _, _, _, _, // 83 |
+ 3, 2, 4, 6, _, // 84 |
+ 4, 0, 2, 4, 6, // 85 |
+ X, _, _, _, _, // 86 |
+ X, _, _, _, _, // 87 |
+ X, _, _, _, _, // 88 |
+ X, _, _, _, _, // 89 |
+ X, _, _, _, _, // 90 |
+ X, _, _, _, _, // 91 |
+ X, _, _, _, _, // 92 |
+ X, _, _, _, _, // 93 |
+ X, _, _, _, _, // 94 |
+ X, _, _, _, _, // 95 |
+ X, _, _, _, _, // 96 |
+ X, _, _, _, _, // 97 |
+ X, _, _, _, _, // 98 |
+ X, _, _, _, _, // 99 |
+ X, _, _, _, _, // 100 |
+ X, _, _, _, _, // 101 |
+ X, _, _, _, _, // 102 |
+ X, _, _, _, _, // 103 |
+ X, _, _, _, _, // 104 |
+ X, _, _, _, _, // 105 |
+ X, _, _, _, _, // 106 |
+ X, _, _, _, _, // 107 |
+ X, _, _, _, _, // 108 |
+ X, _, _, _, _, // 109 |
+ X, _, _, _, _, // 110 |
+ X, _, _, _, _, // 111 |
+ X, _, _, _, _, // 112 |
+ X, _, _, _, _, // 113 |
+ X, _, _, _, _, // 114 |
+ X, _, _, _, _, // 115 |
+ X, _, _, _, _, // 116 |
+ X, _, _, _, _, // 117 |
+ X, _, _, _, _, // 118 |
+ X, _, _, _, _, // 119 |
+ X, _, _, _, _, // 120 |
+ X, _, _, _, _, // 121 |
+ X, _, _, _, _, // 122 |
+ X, _, _, _, _, // 123 |
+ X, _, _, _, _, // 124 |
+ X, _, _, _, _, // 125 |
+ X, _, _, _, _, // 126 |
+ X, _, _, _, _, // 127 |
+ 1, 7, _, _, _, // 128 |
+ 2, 0, 7, _, _, // 129 |
+ 2, 1, 7, _, _, // 130 |
+ X, _, _, _, _, // 131 |
+ 2, 2, 7, _, _, // 132 |
+ 3, 0, 2, 7, _, // 133 |
+ X, _, _, _, _, // 134 |
+ X, _, _, _, _, // 135 |
+ 2, 3, 7, _, _, // 136 |
+ 3, 0, 3, 7, _, // 137 |
+ 3, 1, 3, 7, _, // 138 |
+ X, _, _, _, _, // 139 |
+ X, _, _, _, _, // 140 |
+ X, _, _, _, _, // 141 |
+ X, _, _, _, _, // 142 |
+ X, _, _, _, _, // 143 |
+ 2, 4, 7, _, _, // 144 |
+ 3, 0, 4, 7, _, // 145 |
+ 3, 1, 4, 7, _, // 146 |
+ X, _, _, _, _, // 147 |
+ 3, 2, 4, 7, _, // 148 |
+ 4, 0, 2, 4, 7, // 149 |
+ X, _, _, _, _, // 150 |
+ X, _, _, _, _, // 151 |
+ X, _, _, _, _, // 152 |
+ X, _, _, _, _, // 153 |
+ X, _, _, _, _, // 154 |
+ X, _, _, _, _, // 155 |
+ X, _, _, _, _, // 156 |
+ X, _, _, _, _, // 157 |
+ X, _, _, _, _, // 158 |
+ X, _, _, _, _, // 159 |
+ 2, 5, 7, _, _, // 160 |
+ 3, 0, 5, 7, _, // 161 |
+ 3, 1, 5, 7, _, // 162 |
+ X, _, _, _, _, // 163 |
+ 3, 2, 5, 7, _, // 164 |
+ 4, 0, 2, 5, 7, // 165 |
+ X, _, _, _, _, // 166 |
+ X, _, _, _, _, // 167 |
+ 3, 3, 5, 7, _, // 168 |
+ 4, 0, 3, 5, 7, // 169 |
+ 4, 1, 3, 5, 7 // 170 |
+}; |
+#undef _ |
+#undef X |
+ |
+ |
+// Takes a word of mark bits. Returns the number of objects that start in the |
+// range. Puts the offsets of the words in the supplied array. |
+static inline int MarkWordToObjectStarts(uint32_t mark_bits, int* starts) { |
+ int objects = 0; |
+ int offset = 0; |
+ |
+ // No consecutive 1 bits. |
+ ASSERT((mark_bits & 0x180) != 0x180); |
+ ASSERT((mark_bits & 0x18000) != 0x18000); |
+ ASSERT((mark_bits & 0x1800000) != 0x1800000); |
+ |
+ while (mark_bits != 0) { |
+ int byte = (mark_bits & 0xff); |
+ mark_bits >>= 8; |
+ if (byte != 0) { |
+ ASSERT(byte < kStartTableSize); // No consecutive 1 bits. |
+ char* table = kStartTable + byte * kStartTableStride; |
+ int objects_in_these_8_words = table[0]; |
+ ASSERT(objects_in_these_8_words != kStartTableInvalidEntry); |
+ ASSERT(objects_in_these_8_words < kStartTableStride); |
+ for (int i = 0; i < objects_in_these_8_words; i++) { |
+ starts[objects++] = offset + table[1 + i]; |
+ } |
+ } |
+ offset += 8; |
+ } |
+ return objects; |
+} |
+ |
+ |
+static inline Address DigestFreeStart(Address approximate_free_start, |
+ uint32_t free_start_cell) { |
+ ASSERT(free_start_cell != 0); |
+ |
+ int offsets[16]; |
+ uint32_t cell = free_start_cell; |
+ int offset_of_last_live; |
+ if ((cell & 0x80000000u) != 0) { |
+ // This case would overflow below. |
+ offset_of_last_live = 31; |
+ } else { |
+ // Remove all but one bit, the most significant. This is an optimization |
+ // that may or may not be worthwhile. |
+ cell |= cell >> 16; |
+ cell |= cell >> 8; |
+ cell |= cell >> 4; |
+ cell |= cell >> 2; |
+ cell |= cell >> 1; |
+ cell = (cell + 1) >> 1; |
+ int live_objects = MarkWordToObjectStarts(cell, offsets); |
+ ASSERT(live_objects == 1); |
+ offset_of_last_live = offsets[live_objects - 1]; |
+ } |
+ Address last_live_start = |
+ approximate_free_start + offset_of_last_live * kPointerSize; |
+ HeapObject* last_live = HeapObject::FromAddress(last_live_start); |
+ Address free_start = last_live_start + last_live->Size(); |
+ return free_start; |
+} |
+ |
+ |
+static inline Address StartOfLiveObject(Address block_address, uint32_t cell) { |
+ ASSERT(cell != 0); |
+ |
+ int offsets[16]; |
+ if (cell == 0x80000000u) { // Avoid overflow below. |
+ return block_address + 31 * kPointerSize; |
+ } |
+ uint32_t first_set_bit = ((cell ^ (cell - 1)) + 1) >> 1; |
+ ASSERT((first_set_bit & cell) == first_set_bit); |
+ int live_objects = MarkWordToObjectStarts(first_set_bit, offsets); |
+ ASSERT(live_objects == 1); |
+ USE(live_objects); |
+ return block_address + offsets[0] * kPointerSize; |
+} |
+ |
+ |
+// Sweeps a space conservatively. After this has been done the larger free |
+// spaces have been put on the free list and the smaller ones have been |
+// ignored and left untouched. A free space is always either ignored or put |
+// on the free list, never split up into two parts. This is important |
+// because it means that any ByteArray maps left actually describe a region of |
+// memory that can be ignored when scanning. Dead objects other than byte |
+// arrays will not contain the byte array map. |
static void SweepConservatively(PagedSpace* space, |
- Page* p, |
- Address* last_free_start) { |
- typedef Page::MarkbitsBitmap::CellType CellType; |
+ Page* p) { |
Page::MarkbitsBitmap* markbits = p->markbits(); |
- CellType* cells = markbits->cells(); |
+ Page::MarkbitsBitmap::CellType* cells = markbits->cells(); |
- uint32_t last_cell_index = |
+ p->SetFlag(MemoryChunk::WAS_SWEPT_CONSERVATIVELY); |
+ |
+ // This is the start of the 32 word block that we are currently looking at. |
+ Address block_address = p->ObjectAreaStart(); |
+ |
+ int last_cell_index = |
Page::MarkbitsBitmap::IndexToCell( |
Page::MarkbitsBitmap::CellAlignIndex( |
- p->AddressToMarkbitIndex(p->AllocationTop()))); |
+ p->AddressToMarkbitIndex(p->ObjectAreaEnd()))); |
- uint32_t cell_index = Page::kFirstUsedCell; |
- uint32_t polluted_cell_index = Page::kFirstUsedCell; |
- if (cells[cell_index] == 0) { |
- polluted_cell_index = |
- SweepFree(space, |
- p, |
- p->AddressToMarkbitIndex(p->ObjectAreaStart()), |
- last_cell_index, |
- cells); |
+ int cell_index = Page::kFirstUsedCell; |
- if (polluted_cell_index >= last_cell_index) { |
- // All cells are free. |
- *last_free_start = p->ObjectAreaStart(); |
- return; |
- } |
+ // Skip over all the dead objects at the start of the page and mark them free. |
+ for (cell_index = Page::kFirstUsedCell; |
+ cell_index < last_cell_index; |
+ cell_index++, block_address += 32 * kPointerSize) { |
+ if (cells[cell_index] != 0) break; |
} |
+ int size = block_address - p->ObjectAreaStart(); |
+ if (cell_index == last_cell_index) { |
+ space->Free(p->ObjectAreaStart(), size); |
+ return; |
+ } |
+ // Grow the size of the start-of-page free space a little to get up to the |
+ // first live object. |
+ Address free_end = StartOfLiveObject(block_address, cells[cell_index]); |
+ // Free the first free space. |
+ size = free_end - p->ObjectAreaStart(); |
+ space->Free(p->ObjectAreaStart(), size); |
+ // The start of the current free area is represented in undigested form by |
+ // the address of the last 32-word section that contained a live object and |
+ // the marking bitmap for that cell, which describes where the live object |
+ // started. Unless we find a large free space in the bitmap we will not |
+ // digest this pair into a real address. We start the iteration here at the |
+ // first word in the marking bit map that indicates a live object. |
+ Address free_start = block_address; |
+ uint32_t free_start_cell = cells[cell_index]; |
- p->ClearFlag(Page::IS_CONTINUOUS); |
- |
- ASSERT(cells[polluted_cell_index] != 0); |
- for (cell_index = NextCandidate(polluted_cell_index, last_cell_index, cells); |
+ for ( ; |
cell_index < last_cell_index; |
- cell_index = NextCandidate(polluted_cell_index, |
- last_cell_index, |
- cells)) { |
- ASSERT(cells[cell_index] == 0); |
- |
- int size = SizeOfPreviousObject(p, cell_index, cells); |
- if (size <= 0) { |
- polluted_cell_index = |
- SweepFree(space, |
- p, |
- Page::MarkbitsBitmap::CellToIndex(cell_index), |
- last_cell_index, |
- cells); |
- if (polluted_cell_index >= last_cell_index) { |
- // This free region is the last on the page. |
- *last_free_start = p->MarkbitIndexToAddress( |
- Page::MarkbitsBitmap::CellToIndex(cell_index)); |
- return; |
+ cell_index++, block_address += 32 * kPointerSize) { |
+ ASSERT((unsigned)cell_index == |
+ Page::MarkbitsBitmap::IndexToCell( |
+ Page::MarkbitsBitmap::CellAlignIndex( |
+ p->AddressToMarkbitIndex(block_address)))); |
+ uint32_t cell = cells[cell_index]; |
+ if (cell != 0) { |
+ // We have a live object. Check approximately whether it is more than 32 |
+ // words since the last live object. |
+ if (block_address - free_start > 32 * kPointerSize) { |
+ free_start = DigestFreeStart(free_start, free_start_cell); |
+ if (block_address - free_start > 32 * kPointerSize) { |
+ // Now that we know the exact start of the free space it still looks |
+ // like we have a large enough free space to be worth bothering with. |
+ // so now we need to find the start of the first live object at the |
+ // end of the free space. |
+ free_end = StartOfLiveObject(block_address, cell); |
+ space->Free(free_start, free_end - free_start); |
+ } |
} |
- } else { |
- // Skip cells covered by this object. |
- polluted_cell_index = cell_index + |
- Page::MarkbitsBitmap::IndexToCell(size - 1); |
+ // Update our undigested record of where the current free area started. |
+ free_start = block_address; |
+ free_start_cell = cell; |
} |
} |
+ |
+ // Handle the free space at the end of the page. |
+ if (block_address - free_start > 32 * kPointerSize) { |
+ free_start = DigestFreeStart(free_start, free_start_cell); |
+ space->Free(free_start, block_address - free_start); |
+ } |
} |
+// Sweep a space precisely. After this has been done the space can |
+// be iterated precisely, hitting only the live objects. Code space |
+// is always swept precisely because we want to be able to iterate |
+// over it. Map space is swept precisely, because it is not compacted. |
static void SweepPrecisely(PagedSpace* space, |
- Page* p, |
- Address* last_free_start) { |
- bool is_previous_alive = true; |
- Address free_start = NULL; |
- HeapObject* object; |
+ Page* p) { |
+ Page::MarkbitsBitmap* markbits = p->markbits(); |
+ Page::MarkbitsBitmap::CellType* cells = markbits->cells(); |
- for (Address current = p->ObjectAreaStart(); |
- current < p->AllocationTop(); |
- current += object->Size()) { |
- object = HeapObject::FromAddress(current); |
- if (Marking::IsMarked(object)) { |
- Marking::ClearMark(object); |
- MarkCompactCollector::tracer()->decrement_marked_count(); |
+ p->ClearFlag(MemoryChunk::WAS_SWEPT_CONSERVATIVELY); |
- if (!is_previous_alive) { // Transition from free to live. |
- space->DeallocateBlock(free_start, |
- static_cast<int>(current - free_start), |
- true); |
- is_previous_alive = true; |
+ int last_cell_index = |
+ Page::MarkbitsBitmap::IndexToCell( |
+ Page::MarkbitsBitmap::CellAlignIndex( |
+ p->AddressToMarkbitIndex(p->ObjectAreaEnd()))); |
+ |
+ int cell_index = Page::kFirstUsedCell; |
+ Address free_start = p->ObjectAreaStart(); |
+ ASSERT(reinterpret_cast<uint32_t>(free_start) % (32 * kPointerSize) == 0); |
+ Address object_address = p->ObjectAreaStart(); |
+ int offsets[16]; |
+ |
+ for (cell_index = Page::kFirstUsedCell; |
+ cell_index < last_cell_index; |
+ cell_index++, object_address += 32 * kPointerSize) { |
+ ASSERT((unsigned)cell_index == |
+ Page::MarkbitsBitmap::IndexToCell( |
+ Page::MarkbitsBitmap::CellAlignIndex( |
+ p->AddressToMarkbitIndex(object_address)))); |
+ int live_objects = MarkWordToObjectStarts(cells[cell_index], offsets); |
+ int live_index = 0; |
+ for ( ; live_objects != 0; live_objects--) { |
+ Address free_end = object_address + offsets[live_index++] * kPointerSize; |
+ if (free_end != free_start) { |
+ space->Free(free_start, free_end - free_start); |
} |
- } else { |
- ASSERT((current + kPointerSize) >= p->AllocationTop() || |
- object->Size() == kPointerSize || |
- IncrementalMarking::IsWhite(object)); |
- MarkCompactCollector::ReportDeleteIfNeeded(object); |
- if (is_previous_alive) { // Transition from live to free. |
- free_start = current; |
- is_previous_alive = false; |
- } |
+ HeapObject* live_object = HeapObject::FromAddress(free_end); |
+ free_start = free_end + live_object->Size(); |
} |
} |
- |
- if (!is_previous_alive) *last_free_start = free_start; |
+ if (free_start != p->ObjectAreaEnd()) { |
+ space->Free(free_start, p->ObjectAreaEnd() - free_start); |
+ } |
} |
void MarkCompactCollector::SweepSpace(PagedSpace* space, |
SweeperType sweeper) { |
- PageIterator it(space, PageIterator::PAGES_IN_USE); |
+ space->set_was_swept_conservatively(sweeper == CONSERVATIVE); |
+ // We don't have a linear allocation area while sweeping. It will be restored |
+ // on the first allocation after the sweep. |
+ space->SetTop(NULL, NULL); |
+ |
+ space->ClearStats(); |
+ |
+ PageIterator it(space); |
+ |
// During sweeping of paged space we are trying to find longest sequences |
// of pages without live objects and free them (instead of putting them on |
// the free list). |
@@ -2032,117 +2338,19 @@ |
// Page preceding current. |
Page* prev = Page::FromAddress(NULL); |
- // First empty page in a sequence. |
- Page* first_empty_page = Page::FromAddress(NULL); |
- |
- // Page preceding first empty page. |
- Page* prec_first_empty_page = Page::FromAddress(NULL); |
- |
- // If last used page of space ends with a sequence of dead objects |
- // we can adjust allocation top instead of puting this free area into |
- // the free list. Thus during sweeping we keep track of such areas |
- // and defer their deallocation until the sweeping of the next page |
- // is done: if one of the next pages contains live objects we have |
- // to put such area into the free list. |
- Address last_free_start = NULL; |
- int last_free_size = 0; |
- |
while (it.has_next()) { |
Page* p = it.next(); |
+ space->IncreaseCapacity(p->ObjectAreaEnd() - p->ObjectAreaStart()); |
- Address free_start = p->AllocationTop(); |
- |
if (sweeper == CONSERVATIVE) { |
- SweepConservatively(space, p, &free_start); |
- p->set_linearity_boundary(free_start); |
+ SweepConservatively(space, p); |
} else { |
ASSERT(sweeper == PRECISE); |
- SweepPrecisely(space, p, &free_start); |
+ SweepPrecisely(space, p); |
} |
- |
- bool page_is_empty = (p->ObjectAreaStart() == free_start); |
- bool is_previous_alive = (free_start == p->AllocationTop()); |
- |
- ASSERT(free_start <= p->AllocationTop()); |
- |
- if (page_is_empty) { |
- // This page is empty. Check whether we are in the middle of |
- // sequence of empty pages and start one if not. |
- if (!first_empty_page->is_valid()) { |
- first_empty_page = p; |
- prec_first_empty_page = prev; |
- } |
- |
- if (!is_previous_alive) { |
- // There are dead objects on this page. Update space accounting stats |
- // without putting anything into free list. |
- int size_in_bytes = static_cast<int>(p->AllocationTop() - free_start); |
- if (size_in_bytes > 0) { |
- space->DeallocateBlock(free_start, size_in_bytes, false); |
- } |
- } |
- } else { |
- // This page is not empty. Sequence of empty pages ended on the previous |
- // one. |
- if (first_empty_page->is_valid()) { |
- space->FreePages(prec_first_empty_page, prev); |
- prec_first_empty_page = first_empty_page = Page::FromAddress(NULL); |
- } |
- |
- // If there is a free ending area on one of the previous pages we have |
- // deallocate that area and put it on the free list. |
- if (last_free_size > 0) { |
- Page::FromAddress(last_free_start)-> |
- SetAllocationWatermark(last_free_start); |
- space->DeallocateBlock(last_free_start, last_free_size, true); |
- last_free_start = NULL; |
- last_free_size = 0; |
- } |
- |
- // If the last region of this page was not live we remember it. |
- if (!is_previous_alive) { |
- ASSERT(last_free_size == 0); |
- last_free_size = static_cast<int>(p->AllocationTop() - free_start); |
- last_free_start = free_start; |
- } |
- } |
- |
prev = p; |
} |
- |
- // We reached end of space. See if we need to adjust allocation top. |
- Address new_allocation_top = NULL; |
- |
- if (first_empty_page->is_valid()) { |
- // Last used pages in space are empty. We can move allocation top backwards |
- // to the beginning of first empty page. |
- ASSERT(prev == space->AllocationTopPage()); |
- space->FreePages(prec_first_empty_page, prev); |
- new_allocation_top = first_empty_page->ObjectAreaStart(); |
- } |
- |
- if (last_free_size > 0) { |
- // There was a free ending area on the previous page. |
- // Deallocate it without putting it into freelist and move allocation |
- // top to the beginning of this free area. |
- space->DeallocateBlock(last_free_start, last_free_size, false); |
- new_allocation_top = last_free_start; |
- } |
- |
- if (new_allocation_top != NULL) { |
-#ifdef DEBUG |
- Page* new_allocation_top_page = Page::FromAllocationTop(new_allocation_top); |
- if (!first_empty_page->is_valid()) { |
- ASSERT(new_allocation_top_page == space->AllocationTopPage()); |
- } else if (last_free_size > 0) { |
- ASSERT(new_allocation_top_page == prec_first_empty_page); |
- } else { |
- ASSERT(new_allocation_top_page == first_empty_page); |
- } |
-#endif |
- |
- space->SetTop(new_allocation_top); |
- } |
+ // TODO(gc): set up allocation top and limit using the free list. |
} |
@@ -2152,23 +2360,19 @@ |
state_ = SWEEP_SPACES; |
#endif |
-#ifndef DEBUG |
- SweeperType fast_sweeper = CONSERVATIVE; |
-#else |
- SweeperType fast_sweeper = PRECISE; |
-#endif |
- |
ASSERT(!IsCompacting()); |
+ SweeperType how_to_sweep = CONSERVATIVE; |
+ if (sweep_precisely_) how_to_sweep = PRECISE; |
// Noncompacting collections simply sweep the spaces to clear the mark |
// bits and free the nonlive blocks (for old and map spaces). We sweep |
// the map space last because freeing non-live maps overwrites them and |
// the other spaces rely on possibly non-live maps to get the sizes for |
// non-live objects. |
- SweepSpace(Heap::old_pointer_space(), fast_sweeper); |
- SweepSpace(Heap::old_data_space(), fast_sweeper); |
+ SweepSpace(Heap::old_pointer_space(), how_to_sweep); |
+ SweepSpace(Heap::old_data_space(), how_to_sweep); |
SweepSpace(Heap::code_space(), PRECISE); |
// TODO(gc): implement specialized sweeper for cell space. |
- SweepSpace(Heap::cell_space(), fast_sweeper); |
+ SweepSpace(Heap::cell_space(), PRECISE); |
{ GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE); |
SweepNewSpace(Heap::new_space()); |
} |
@@ -2222,12 +2426,13 @@ |
int MarkCompactCollector::IterateLiveObjects(PagedSpace* space, |
HeapObjectCallback size_f) { |
ASSERT(MARK_LIVE_OBJECTS < state_ && state_ <= RELOCATE_OBJECTS); |
+ // TODO(gc): Do a mark-sweep first with precise sweeping. |
int total = 0; |
- PageIterator it(space, PageIterator::PAGES_IN_USE); |
+ PageIterator it(space); |
while (it.has_next()) { |
Page* p = it.next(); |
total += IterateLiveObjectsInRange(p->ObjectAreaStart(), |
- p->AllocationTop(), |
+ p->ObjectAreaEnd(), |
size_f); |
} |
return total; |