Index: src/spaces.cc |
diff --git a/src/spaces.cc b/src/spaces.cc |
index 6b6d926e257153f35de2453e9359cb9faf772f0a..1d868e9ac731d32a7c354bf8b8b8c6098ce322ec 100644 |
--- a/src/spaces.cc |
+++ b/src/spaces.cc |
@@ -41,6 +41,7 @@ namespace internal { |
&& (info).top <= (space).high() \ |
&& (info).limit == (space).high()) |
+intptr_t Page::watermark_invalidated_mark_ = Page::WATERMARK_INVALIDATED; |
// ---------------------------------------------------------------------------- |
// HeapObjectIterator |
@@ -139,13 +140,6 @@ PageIterator::PageIterator(PagedSpace* space, Mode mode) : space_(space) { |
// ----------------------------------------------------------------------------- |
-// Page |
- |
-#ifdef DEBUG |
-Page::RSetState Page::rset_state_ = Page::IN_USE; |
-#endif |
- |
-// ----------------------------------------------------------------------------- |
// CodeRange |
List<CodeRange::FreeBlock> CodeRange::free_list_(0); |
@@ -524,7 +518,10 @@ Page* MemoryAllocator::InitializePagesInChunk(int chunk_id, int pages_in_chunk, |
for (int i = 0; i < pages_in_chunk; i++) { |
Page* p = Page::FromAddress(page_addr); |
p->opaque_header = OffsetFrom(page_addr + Page::kPageSize) | chunk_id; |
+ p->InvalidateWatermark(true); |
p->SetIsLargeObjectPage(false); |
+ p->SetAllocationWatermark(p->ObjectAreaStart()); |
+ p->SetCachedAllocationWatermark(p->ObjectAreaStart()); |
page_addr += Page::kPageSize; |
} |
@@ -681,6 +678,7 @@ Page* MemoryAllocator::RelinkPagesInChunk(int chunk_id, |
p->opaque_header = OffsetFrom(page_addr + Page::kPageSize) | chunk_id; |
page_addr += Page::kPageSize; |
+ p->InvalidateWatermark(true); |
if (p->WasInUseBeforeMC()) { |
*last_page_in_use = p; |
} |
@@ -744,10 +742,10 @@ bool PagedSpace::Setup(Address start, size_t size) { |
accounting_stats_.ExpandSpace(num_pages * Page::kObjectAreaSize); |
ASSERT(Capacity() <= max_capacity_); |
- // Sequentially initialize remembered sets in the newly allocated |
+ // Sequentially clear region marks in the newly allocated |
// pages and cache the current last page in the space. |
for (Page* p = first_page_; p->is_valid(); p = p->next_page()) { |
- p->ClearRSet(); |
+ p->SetRegionMarks(Page::kAllRegionsCleanMarks); |
last_page_ = p; |
} |
@@ -794,10 +792,10 @@ void PagedSpace::Unprotect() { |
#endif |
-void PagedSpace::ClearRSet() { |
+void PagedSpace::MarkAllPagesClean() { |
PageIterator it(this, PageIterator::ALL_PAGES); |
while (it.has_next()) { |
- it.next()->ClearRSet(); |
+ it.next()->SetRegionMarks(Page::kAllRegionsCleanMarks); |
} |
} |
@@ -900,7 +898,8 @@ HeapObject* PagedSpace::SlowMCAllocateRaw(int size_in_bytes) { |
// of forwarding addresses is as an offset in terms of live bytes, so we |
// need quick access to the allocation top of each page to decode |
// forwarding addresses. |
- current_page->mc_relocation_top = mc_forwarding_info_.top; |
+ current_page->SetAllocationWatermark(mc_forwarding_info_.top); |
+ current_page->next_page()->InvalidateWatermark(true); |
SetAllocationInfo(&mc_forwarding_info_, current_page->next_page()); |
return AllocateLinearly(&mc_forwarding_info_, size_in_bytes); |
} |
@@ -928,10 +927,10 @@ bool PagedSpace::Expand(Page* last_page) { |
MemoryAllocator::SetNextPage(last_page, p); |
- // Sequentially clear remembered set of new pages and and cache the |
+ // Sequentially clear region marks of new pages and and cache the |
// new last page in the space. |
while (p->is_valid()) { |
- p->ClearRSet(); |
+ p->SetRegionMarks(Page::kAllRegionsCleanMarks); |
last_page_ = p; |
p = p->next_page(); |
} |
@@ -1030,16 +1029,11 @@ void PagedSpace::Verify(ObjectVisitor* visitor) { |
if (above_allocation_top) { |
// We don't care what's above the allocation top. |
} else { |
- // Unless this is the last page in the space containing allocated |
- // objects, the allocation top should be at a constant offset from the |
- // object area end. |
Address top = current_page->AllocationTop(); |
if (current_page == top_page) { |
ASSERT(top == allocation_info_.top); |
// The next page will be above the allocation top. |
above_allocation_top = true; |
- } else { |
- ASSERT(top == PageAllocationLimit(current_page)); |
} |
// It should be packed with objects from the bottom to the top. |
@@ -1060,8 +1054,8 @@ void PagedSpace::Verify(ObjectVisitor* visitor) { |
object->Verify(); |
// All the interior pointers should be contained in the heap and |
- // have their remembered set bits set if required as determined |
- // by the visitor. |
+ // have page regions covering intergenerational references should be |
+ // marked dirty. |
int size = object->Size(); |
object->IterateBody(map->instance_type(), size, visitor); |
@@ -1120,7 +1114,7 @@ bool NewSpace::Setup(Address start, int size) { |
start_ = start; |
address_mask_ = ~(size - 1); |
- object_mask_ = address_mask_ | kHeapObjectTag; |
+ object_mask_ = address_mask_ | kHeapObjectTagMask; |
object_expected_ = reinterpret_cast<uintptr_t>(start) | kHeapObjectTag; |
allocation_info_.top = to_space_.low(); |
@@ -1324,7 +1318,7 @@ bool SemiSpace::Setup(Address start, |
start_ = start; |
address_mask_ = ~(maximum_capacity - 1); |
- object_mask_ = address_mask_ | kHeapObjectTag; |
+ object_mask_ = address_mask_ | kHeapObjectTagMask; |
object_expected_ = reinterpret_cast<uintptr_t>(start) | kHeapObjectTag; |
age_mark_ = start_; |
@@ -1634,7 +1628,7 @@ void FreeListNode::set_size(int size_in_bytes) { |
// If the block is too small (eg, one or two words), to hold both a size |
// field and a next pointer, we give it a filler map that gives it the |
// correct size. |
- if (size_in_bytes > ByteArray::kAlignedSize) { |
+ if (size_in_bytes > ByteArray::kHeaderSize) { |
set_map(Heap::raw_unchecked_byte_array_map()); |
// Can't use ByteArray::cast because it fails during deserialization. |
ByteArray* this_as_byte_array = reinterpret_cast<ByteArray*>(this); |
@@ -1831,7 +1825,7 @@ FixedSizeFreeList::FixedSizeFreeList(AllocationSpace owner, int object_size) |
void FixedSizeFreeList::Reset() { |
available_ = 0; |
- head_ = NULL; |
+ head_ = tail_ = NULL; |
} |
@@ -1843,8 +1837,13 @@ void FixedSizeFreeList::Free(Address start) { |
ASSERT(!MarkCompactCollector::IsCompacting()); |
FreeListNode* node = FreeListNode::FromAddress(start); |
node->set_size(object_size_); |
- node->set_next(head_); |
- head_ = node->address(); |
+ node->set_next(NULL); |
+ if (head_ == NULL) { |
+ tail_ = head_ = node->address(); |
+ } else { |
+ FreeListNode::FromAddress(tail_)->set_next(node->address()); |
+ tail_ = node->address(); |
+ } |
available_ += object_size_; |
} |
@@ -1907,15 +1906,14 @@ void OldSpace::MCCommitRelocationInfo() { |
Page* p = it.next(); |
// Space below the relocation pointer is allocated. |
computed_size += |
- static_cast<int>(p->mc_relocation_top - p->ObjectAreaStart()); |
+ static_cast<int>(p->AllocationWatermark() - p->ObjectAreaStart()); |
if (it.has_next()) { |
- // Free the space at the top of the page. We cannot use |
- // p->mc_relocation_top after the call to Free (because Free will clear |
- // remembered set bits). |
+ // Free the space at the top of the page. |
int extra_size = |
- static_cast<int>(p->ObjectAreaEnd() - p->mc_relocation_top); |
+ static_cast<int>(p->ObjectAreaEnd() - p->AllocationWatermark()); |
if (extra_size > 0) { |
- int wasted_bytes = free_list_.Free(p->mc_relocation_top, extra_size); |
+ int wasted_bytes = free_list_.Free(p->AllocationWatermark(), |
+ extra_size); |
// The bytes we have just "freed" to add to the free list were |
// already accounted as available. |
accounting_stats_.WasteBytes(wasted_bytes); |
@@ -1963,7 +1961,10 @@ void PagedSpace::FreePages(Page* prev, Page* last) { |
// Clean them up. |
do { |
- first->ClearRSet(); |
+ first->InvalidateWatermark(true); |
+ first->SetAllocationWatermark(first->ObjectAreaStart()); |
+ first->SetCachedAllocationWatermark(first->ObjectAreaStart()); |
+ first->SetRegionMarks(Page::kAllRegionsCleanMarks); |
first = first->next_page(); |
} while (first != NULL); |
@@ -2003,6 +2004,7 @@ void PagedSpace::PrepareForMarkCompact(bool will_compact) { |
// Current allocation top points to a page which is now in the middle |
// of page list. We should move allocation top forward to the new last |
// used page so various object iterators will continue to work properly. |
+ last_in_use->SetAllocationWatermark(last_in_use->AllocationTop()); |
int size_in_bytes = static_cast<int>(PageAllocationLimit(last_in_use) - |
last_in_use->AllocationTop()); |
@@ -2035,6 +2037,7 @@ void PagedSpace::PrepareForMarkCompact(bool will_compact) { |
int size_in_bytes = static_cast<int>(PageAllocationLimit(p) - |
p->ObjectAreaStart()); |
+ p->SetAllocationWatermark(p->ObjectAreaStart()); |
Heap::CreateFillerObjectAt(p->ObjectAreaStart(), size_in_bytes); |
} |
} |
@@ -2066,6 +2069,7 @@ bool PagedSpace::ReserveSpace(int bytes) { |
if (!reserved_page->is_valid()) return false; |
} |
ASSERT(TopPageOf(allocation_info_)->next_page()->is_valid()); |
+ TopPageOf(allocation_info_)->next_page()->InvalidateWatermark(true); |
SetAllocationInfo(&allocation_info_, |
TopPageOf(allocation_info_)->next_page()); |
return true; |
@@ -2100,7 +2104,20 @@ HeapObject* OldSpace::SlowAllocateRaw(int size_in_bytes) { |
accounting_stats_.WasteBytes(wasted_bytes); |
if (!result->IsFailure()) { |
accounting_stats_.AllocateBytes(size_in_bytes); |
- return HeapObject::cast(result); |
+ |
+ HeapObject* obj = HeapObject::cast(result); |
+ Page* p = Page::FromAddress(obj->address()); |
+ |
+ if (obj->address() >= p->AllocationWatermark()) { |
+ // There should be no hole between the allocation watermark |
+ // and allocated object address. |
+ // Memory above the allocation watermark was not swept and |
+ // might contain garbage pointers to new space. |
+ ASSERT(obj->address() == p->AllocationWatermark()); |
+ p->SetAllocationWatermark(obj->address() + size_in_bytes); |
+ } |
+ |
+ return obj; |
} |
} |
@@ -2123,6 +2140,7 @@ HeapObject* OldSpace::SlowAllocateRaw(int size_in_bytes) { |
void OldSpace::PutRestOfCurrentPageOnFreeList(Page* current_page) { |
+ current_page->SetAllocationWatermark(allocation_info_.top); |
int free_size = |
static_cast<int>(current_page->ObjectAreaEnd() - allocation_info_.top); |
if (free_size > 0) { |
@@ -2133,6 +2151,7 @@ void OldSpace::PutRestOfCurrentPageOnFreeList(Page* current_page) { |
void FixedSpace::PutRestOfCurrentPageOnFreeList(Page* current_page) { |
+ current_page->SetAllocationWatermark(allocation_info_.top); |
int free_size = |
static_cast<int>(current_page->ObjectAreaEnd() - allocation_info_.top); |
// In the fixed space free list all the free list items have the right size. |
@@ -2152,8 +2171,10 @@ void FixedSpace::PutRestOfCurrentPageOnFreeList(Page* current_page) { |
HeapObject* OldSpace::AllocateInNextPage(Page* current_page, |
int size_in_bytes) { |
ASSERT(current_page->next_page()->is_valid()); |
+ Page* next_page = current_page->next_page(); |
+ next_page->ClearGCFields(); |
PutRestOfCurrentPageOnFreeList(current_page); |
- SetAllocationInfo(&allocation_info_, current_page->next_page()); |
+ SetAllocationInfo(&allocation_info_, next_page); |
return AllocateLinearly(&allocation_info_, size_in_bytes); |
} |
@@ -2296,160 +2317,12 @@ void OldSpace::ReportStatistics() { |
PrintF(" capacity: %d, waste: %d, available: %d, %%%d\n", |
Capacity(), Waste(), Available(), pct); |
- // Report remembered set statistics. |
- int rset_marked_pointers = 0; |
- int rset_marked_arrays = 0; |
- int rset_marked_array_elements = 0; |
- int cross_gen_pointers = 0; |
- int cross_gen_array_elements = 0; |
- |
- PageIterator page_it(this, PageIterator::PAGES_IN_USE); |
- while (page_it.has_next()) { |
- Page* p = page_it.next(); |
- |
- for (Address rset_addr = p->RSetStart(); |
- rset_addr < p->RSetEnd(); |
- rset_addr += kIntSize) { |
- int rset = Memory::int_at(rset_addr); |
- if (rset != 0) { |
- // Bits were set |
- int intoff = |
- static_cast<int>(rset_addr - p->address() - Page::kRSetOffset); |
- int bitoff = 0; |
- for (; bitoff < kBitsPerInt; ++bitoff) { |
- if ((rset & (1 << bitoff)) != 0) { |
- int bitpos = intoff*kBitsPerByte + bitoff; |
- Address slot = p->OffsetToAddress(bitpos << kObjectAlignmentBits); |
- Object** obj = reinterpret_cast<Object**>(slot); |
- if (*obj == Heap::raw_unchecked_fixed_array_map()) { |
- rset_marked_arrays++; |
- FixedArray* fa = FixedArray::cast(HeapObject::FromAddress(slot)); |
- |
- rset_marked_array_elements += fa->length(); |
- // Manually inline FixedArray::IterateBody |
- Address elm_start = slot + FixedArray::kHeaderSize; |
- Address elm_stop = elm_start + fa->length() * kPointerSize; |
- for (Address elm_addr = elm_start; |
- elm_addr < elm_stop; elm_addr += kPointerSize) { |
- // Filter non-heap-object pointers |
- Object** elm_p = reinterpret_cast<Object**>(elm_addr); |
- if (Heap::InNewSpace(*elm_p)) |
- cross_gen_array_elements++; |
- } |
- } else { |
- rset_marked_pointers++; |
- if (Heap::InNewSpace(*obj)) |
- cross_gen_pointers++; |
- } |
- } |
- } |
- } |
- } |
- } |
- |
- pct = rset_marked_pointers == 0 ? |
- 0 : cross_gen_pointers * 100 / rset_marked_pointers; |
- PrintF(" rset-marked pointers %d, to-new-space %d (%%%d)\n", |
- rset_marked_pointers, cross_gen_pointers, pct); |
- PrintF(" rset_marked arrays %d, ", rset_marked_arrays); |
- PrintF(" elements %d, ", rset_marked_array_elements); |
- pct = rset_marked_array_elements == 0 ? 0 |
- : cross_gen_array_elements * 100 / rset_marked_array_elements; |
- PrintF(" pointers to new space %d (%%%d)\n", cross_gen_array_elements, pct); |
- PrintF(" total rset-marked bits %d\n", |
- (rset_marked_pointers + rset_marked_arrays)); |
- pct = (rset_marked_pointers + rset_marked_array_elements) == 0 ? 0 |
- : (cross_gen_pointers + cross_gen_array_elements) * 100 / |
- (rset_marked_pointers + rset_marked_array_elements); |
- PrintF(" total rset pointers %d, true cross generation ones %d (%%%d)\n", |
- (rset_marked_pointers + rset_marked_array_elements), |
- (cross_gen_pointers + cross_gen_array_elements), |
- pct); |
- |
ClearHistograms(); |
HeapObjectIterator obj_it(this); |
for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next()) |
CollectHistogramInfo(obj); |
ReportHistogram(true); |
} |
- |
- |
-// Dump the range of remembered set words between [start, end) corresponding |
-// to the pointers starting at object_p. The allocation_top is an object |
-// pointer which should not be read past. This is important for large object |
-// pages, where some bits in the remembered set range do not correspond to |
-// allocated addresses. |
-static void PrintRSetRange(Address start, Address end, Object** object_p, |
- Address allocation_top) { |
- Address rset_address = start; |
- |
- // If the range starts on on odd numbered word (eg, for large object extra |
- // remembered set ranges), print some spaces. |
- if ((reinterpret_cast<uintptr_t>(start) / kIntSize) % 2 == 1) { |
- PrintF(" "); |
- } |
- |
- // Loop over all the words in the range. |
- while (rset_address < end) { |
- uint32_t rset_word = Memory::uint32_at(rset_address); |
- int bit_position = 0; |
- |
- // Loop over all the bits in the word. |
- while (bit_position < kBitsPerInt) { |
- if (object_p == reinterpret_cast<Object**>(allocation_top)) { |
- // Print a bar at the allocation pointer. |
- PrintF("|"); |
- } else if (object_p > reinterpret_cast<Object**>(allocation_top)) { |
- // Do not dereference object_p past the allocation pointer. |
- PrintF("#"); |
- } else if ((rset_word & (1 << bit_position)) == 0) { |
- // Print a dot for zero bits. |
- PrintF("."); |
- } else if (Heap::InNewSpace(*object_p)) { |
- // Print an X for one bits for pointers to new space. |
- PrintF("X"); |
- } else { |
- // Print a circle for one bits for pointers to old space. |
- PrintF("o"); |
- } |
- |
- // Print a space after every 8th bit except the last. |
- if (bit_position % 8 == 7 && bit_position != (kBitsPerInt - 1)) { |
- PrintF(" "); |
- } |
- |
- // Advance to next bit. |
- bit_position++; |
- object_p++; |
- } |
- |
- // Print a newline after every odd numbered word, otherwise a space. |
- if ((reinterpret_cast<uintptr_t>(rset_address) / kIntSize) % 2 == 1) { |
- PrintF("\n"); |
- } else { |
- PrintF(" "); |
- } |
- |
- // Advance to next remembered set word. |
- rset_address += kIntSize; |
- } |
-} |
- |
- |
-void PagedSpace::DoPrintRSet(const char* space_name) { |
- PageIterator it(this, PageIterator::PAGES_IN_USE); |
- while (it.has_next()) { |
- Page* p = it.next(); |
- PrintF("%s page 0x%x:\n", space_name, p); |
- PrintRSetRange(p->RSetStart(), p->RSetEnd(), |
- reinterpret_cast<Object**>(p->ObjectAreaStart()), |
- p->AllocationTop()); |
- PrintF("\n"); |
- } |
-} |
- |
- |
-void OldSpace::PrintRSet() { DoPrintRSet("old"); } |
#endif |
// ----------------------------------------------------------------------------- |
@@ -2499,6 +2372,7 @@ void FixedSpace::MCCommitRelocationInfo() { |
if (it.has_next()) { |
accounting_stats_.WasteBytes( |
static_cast<int>(page->ObjectAreaEnd() - page_top)); |
+ page->SetAllocationWatermark(page_top); |
} |
} |
@@ -2528,7 +2402,19 @@ HeapObject* FixedSpace::SlowAllocateRaw(int size_in_bytes) { |
Object* result = free_list_.Allocate(); |
if (!result->IsFailure()) { |
accounting_stats_.AllocateBytes(size_in_bytes); |
- return HeapObject::cast(result); |
+ HeapObject* obj = HeapObject::cast(result); |
+ Page* p = Page::FromAddress(obj->address()); |
+ |
+ if (obj->address() >= p->AllocationWatermark()) { |
+ // There should be no hole between the allocation watermark |
+ // and allocated object address. |
+ // Memory above the allocation watermark was not swept and |
+ // might contain garbage pointers to new space. |
+ ASSERT(obj->address() == p->AllocationWatermark()); |
+ p->SetAllocationWatermark(obj->address() + size_in_bytes); |
+ } |
+ |
+ return obj; |
} |
} |
@@ -2558,8 +2444,11 @@ HeapObject* FixedSpace::AllocateInNextPage(Page* current_page, |
ASSERT(current_page->next_page()->is_valid()); |
ASSERT(allocation_info_.top == PageAllocationLimit(current_page)); |
ASSERT_EQ(object_size_in_bytes_, size_in_bytes); |
+ Page* next_page = current_page->next_page(); |
+ next_page->ClearGCFields(); |
+ current_page->SetAllocationWatermark(allocation_info_.top); |
accounting_stats_.WasteBytes(page_extra_); |
- SetAllocationInfo(&allocation_info_, current_page->next_page()); |
+ SetAllocationInfo(&allocation_info_, next_page); |
return AllocateLinearly(&allocation_info_, size_in_bytes); |
} |
@@ -2570,51 +2459,12 @@ void FixedSpace::ReportStatistics() { |
PrintF(" capacity: %d, waste: %d, available: %d, %%%d\n", |
Capacity(), Waste(), Available(), pct); |
- // Report remembered set statistics. |
- int rset_marked_pointers = 0; |
- int cross_gen_pointers = 0; |
- |
- PageIterator page_it(this, PageIterator::PAGES_IN_USE); |
- while (page_it.has_next()) { |
- Page* p = page_it.next(); |
- |
- for (Address rset_addr = p->RSetStart(); |
- rset_addr < p->RSetEnd(); |
- rset_addr += kIntSize) { |
- int rset = Memory::int_at(rset_addr); |
- if (rset != 0) { |
- // Bits were set |
- int intoff = |
- static_cast<int>(rset_addr - p->address() - Page::kRSetOffset); |
- int bitoff = 0; |
- for (; bitoff < kBitsPerInt; ++bitoff) { |
- if ((rset & (1 << bitoff)) != 0) { |
- int bitpos = intoff*kBitsPerByte + bitoff; |
- Address slot = p->OffsetToAddress(bitpos << kObjectAlignmentBits); |
- Object** obj = reinterpret_cast<Object**>(slot); |
- rset_marked_pointers++; |
- if (Heap::InNewSpace(*obj)) |
- cross_gen_pointers++; |
- } |
- } |
- } |
- } |
- } |
- |
- pct = rset_marked_pointers == 0 ? |
- 0 : cross_gen_pointers * 100 / rset_marked_pointers; |
- PrintF(" rset-marked pointers %d, to-new-space %d (%%%d)\n", |
- rset_marked_pointers, cross_gen_pointers, pct); |
- |
ClearHistograms(); |
HeapObjectIterator obj_it(this); |
for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next()) |
CollectHistogramInfo(obj); |
ReportHistogram(false); |
} |
- |
- |
-void FixedSpace::PrintRSet() { DoPrintRSet(name_); } |
#endif |
@@ -2793,8 +2643,7 @@ Object* LargeObjectSpace::AllocateRawInternal(int requested_size, |
chunk->set_size(chunk_size); |
first_chunk_ = chunk; |
- // Set the object address and size in the page header and clear its |
- // remembered set. |
+ // Initialize page header. |
Page* page = Page::FromAddress(RoundUp(chunk->address(), Page::kPageSize)); |
Address object_address = page->ObjectAreaStart(); |
// Clear the low order bit of the second word in the page to flag it as a |
@@ -2802,13 +2651,7 @@ Object* LargeObjectSpace::AllocateRawInternal(int requested_size, |
// low order bit should already be clear. |
ASSERT((chunk_size & 0x1) == 0); |
page->SetIsLargeObjectPage(true); |
- page->ClearRSet(); |
- int extra_bytes = requested_size - object_size; |
- if (extra_bytes > 0) { |
- // The extra memory for the remembered set should be cleared. |
- memset(object_address + object_size, 0, extra_bytes); |
- } |
- |
+ page->SetRegionMarks(Page::kAllRegionsCleanMarks); |
return HeapObject::FromAddress(object_address); |
} |
@@ -2823,8 +2666,7 @@ Object* LargeObjectSpace::AllocateRawCode(int size_in_bytes) { |
Object* LargeObjectSpace::AllocateRawFixedArray(int size_in_bytes) { |
ASSERT(0 < size_in_bytes); |
- int extra_rset_bytes = ExtraRSetBytesFor(size_in_bytes); |
- return AllocateRawInternal(size_in_bytes + extra_rset_bytes, |
+ return AllocateRawInternal(size_in_bytes, |
size_in_bytes, |
NOT_EXECUTABLE); |
} |
@@ -2851,59 +2693,61 @@ Object* LargeObjectSpace::FindObject(Address a) { |
return Failure::Exception(); |
} |
- |
-void LargeObjectSpace::ClearRSet() { |
- ASSERT(Page::is_rset_in_use()); |
- |
- LargeObjectIterator it(this); |
- for (HeapObject* object = it.next(); object != NULL; object = it.next()) { |
- // We only have code, sequential strings, or fixed arrays in large |
- // object space, and only fixed arrays need remembered set support. |
- if (object->IsFixedArray()) { |
- // Clear the normal remembered set region of the page; |
- Page* page = Page::FromAddress(object->address()); |
- page->ClearRSet(); |
- |
- // Clear the extra remembered set. |
- int size = object->Size(); |
- int extra_rset_bytes = ExtraRSetBytesFor(size); |
- memset(object->address() + size, 0, extra_rset_bytes); |
- } |
- } |
-} |
- |
- |
-void LargeObjectSpace::IterateRSet(ObjectSlotCallback copy_object_func) { |
- ASSERT(Page::is_rset_in_use()); |
- |
- static void* lo_rset_histogram = StatsTable::CreateHistogram( |
- "V8.RSetLO", |
- 0, |
- // Keeping this histogram's buckets the same as the paged space histogram. |
- Page::kObjectAreaSize / kPointerSize, |
- 30); |
- |
+void LargeObjectSpace::IterateDirtyRegions(ObjectSlotCallback copy_object) { |
LargeObjectIterator it(this); |
for (HeapObject* object = it.next(); object != NULL; object = it.next()) { |
// We only have code, sequential strings, or fixed arrays in large |
// object space, and only fixed arrays can possibly contain pointers to |
// the young generation. |
if (object->IsFixedArray()) { |
- // Iterate the normal page remembered set range. |
Page* page = Page::FromAddress(object->address()); |
- Address object_end = object->address() + object->Size(); |
- int count = Heap::IterateRSetRange(page->ObjectAreaStart(), |
- Min(page->ObjectAreaEnd(), object_end), |
- page->RSetStart(), |
- copy_object_func); |
- |
- // Iterate the extra array elements. |
- if (object_end > page->ObjectAreaEnd()) { |
- count += Heap::IterateRSetRange(page->ObjectAreaEnd(), object_end, |
- object_end, copy_object_func); |
- } |
- if (lo_rset_histogram != NULL) { |
- StatsTable::AddHistogramSample(lo_rset_histogram, count); |
+ uint32_t marks = page->GetRegionMarks(); |
+ uint32_t newmarks = Page::kAllRegionsCleanMarks; |
+ |
+ if (marks != Page::kAllRegionsCleanMarks) { |
+ // For a large page a single dirty mark corresponds to several |
+ // regions (modulo 32). So we treat a large page as a sequence of |
+ // normal pages of size Page::kPageSize having same dirty marks |
+ // and subsequently iterate dirty regions on each of these pages. |
+ Address start = object->address(); |
+ Address end = page->ObjectAreaEnd(); |
+ Address object_end = start + object->Size(); |
+ |
+ // Iterate regions of the first normal page covering object. |
+ uint32_t first_region_number = page->GetRegionNumberForAddress(start); |
+ newmarks |= |
+ Heap::IterateDirtyRegions(marks >> first_region_number, |
+ start, |
+ end, |
+ &Heap::IteratePointersInDirtyRegion, |
+ copy_object) << first_region_number; |
+ |
+ start = end; |
+ end = start + Page::kPageSize; |
+ while (end <= object_end) { |
+ // Iterate next 32 regions. |
+ newmarks |= |
+ Heap::IterateDirtyRegions(marks, |
+ start, |
+ end, |
+ &Heap::IteratePointersInDirtyRegion, |
+ copy_object); |
+ start = end; |
+ end = start + Page::kPageSize; |
+ } |
+ |
+ if (start != object_end) { |
+ // Iterate the last piece of an object which is less than |
+ // Page::kPageSize. |
+ newmarks |= |
+ Heap::IterateDirtyRegions(marks, |
+ start, |
+ object_end, |
+ &Heap::IteratePointersInDirtyRegion, |
+ copy_object); |
+ } |
+ |
+ page->SetRegionMarks(newmarks); |
} |
} |
} |
@@ -2995,7 +2839,7 @@ void LargeObjectSpace::Verify() { |
} else if (object->IsFixedArray()) { |
// We loop over fixed arrays ourselves, rather then using the visitor, |
// because the visitor doesn't support the start/offset iteration |
- // needed for IsRSetSet. |
+ // needed for IsRegionDirty. |
FixedArray* array = FixedArray::cast(object); |
for (int j = 0; j < array->length(); j++) { |
Object* element = array->get(j); |
@@ -3004,8 +2848,11 @@ void LargeObjectSpace::Verify() { |
ASSERT(Heap::Contains(element_object)); |
ASSERT(element_object->map()->IsMap()); |
if (Heap::InNewSpace(element_object)) { |
- ASSERT(Page::IsRSetSet(object->address(), |
- FixedArray::kHeaderSize + j * kPointerSize)); |
+ Address array_addr = object->address(); |
+ Address element_addr = array_addr + FixedArray::kHeaderSize + |
+ j * kPointerSize; |
+ |
+ ASSERT(Page::FromAddress(array_addr)->IsRegionDirty(element_addr)); |
} |
} |
} |
@@ -3046,33 +2893,6 @@ void LargeObjectSpace::CollectCodeStatistics() { |
} |
} |
} |
- |
- |
-void LargeObjectSpace::PrintRSet() { |
- LargeObjectIterator it(this); |
- for (HeapObject* object = it.next(); object != NULL; object = it.next()) { |
- if (object->IsFixedArray()) { |
- Page* page = Page::FromAddress(object->address()); |
- |
- Address allocation_top = object->address() + object->Size(); |
- PrintF("large page 0x%x:\n", page); |
- PrintRSetRange(page->RSetStart(), page->RSetEnd(), |
- reinterpret_cast<Object**>(object->address()), |
- allocation_top); |
- int extra_array_bytes = object->Size() - Page::kObjectAreaSize; |
- int extra_rset_bits = RoundUp(extra_array_bytes / kPointerSize, |
- kBitsPerInt); |
- PrintF("------------------------------------------------------------" |
- "-----------\n"); |
- PrintRSetRange(allocation_top, |
- allocation_top + extra_rset_bits / kBitsPerByte, |
- reinterpret_cast<Object**>(object->address() |
- + Page::kObjectAreaSize), |
- allocation_top); |
- PrintF("\n"); |
- } |
- } |
-} |
#endif // DEBUG |
} } // namespace v8::internal |