Index: src/spaces.cc |
=================================================================== |
--- src/spaces.cc (revision 4686) |
+++ src/spaces.cc (working copy) |
@@ -41,7 +41,6 @@ |
&& (info).top <= (space).high() \ |
&& (info).limit == (space).high()) |
-intptr_t Page::watermark_invalidated_mark_ = Page::WATERMARK_INVALIDATED; |
// ---------------------------------------------------------------------------- |
// HeapObjectIterator |
@@ -140,6 +139,13 @@ |
// ----------------------------------------------------------------------------- |
+// Page |
+ |
+#ifdef DEBUG |
+Page::RSetState Page::rset_state_ = Page::IN_USE; |
+#endif |
+ |
+// ----------------------------------------------------------------------------- |
// CodeRange |
List<CodeRange::FreeBlock> CodeRange::free_list_(0); |
@@ -518,10 +524,7 @@ |
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; |
} |
@@ -678,7 +681,6 @@ |
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; |
} |
@@ -742,10 +744,10 @@ |
accounting_stats_.ExpandSpace(num_pages * Page::kObjectAreaSize); |
ASSERT(Capacity() <= max_capacity_); |
- // Sequentially clear region marks in the newly allocated |
+ // Sequentially initialize remembered sets 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->SetRegionMarks(Page::kAllRegionsCleanMarks); |
+ p->ClearRSet(); |
last_page_ = p; |
} |
@@ -792,10 +794,10 @@ |
#endif |
-void PagedSpace::MarkAllPagesClean() { |
+void PagedSpace::ClearRSet() { |
PageIterator it(this, PageIterator::ALL_PAGES); |
while (it.has_next()) { |
- it.next()->SetRegionMarks(Page::kAllRegionsCleanMarks); |
+ it.next()->ClearRSet(); |
} |
} |
@@ -898,8 +900,7 @@ |
// 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->SetAllocationWatermark(mc_forwarding_info_.top); |
- current_page->next_page()->InvalidateWatermark(true); |
+ current_page->mc_relocation_top = mc_forwarding_info_.top; |
SetAllocationInfo(&mc_forwarding_info_, current_page->next_page()); |
return AllocateLinearly(&mc_forwarding_info_, size_in_bytes); |
} |
@@ -927,10 +928,10 @@ |
MemoryAllocator::SetNextPage(last_page, p); |
- // Sequentially clear region marks of new pages and and cache the |
+ // Sequentially clear remembered set of new pages and and cache the |
// new last page in the space. |
while (p->is_valid()) { |
- p->SetRegionMarks(Page::kAllRegionsCleanMarks); |
+ p->ClearRSet(); |
last_page_ = p; |
p = p->next_page(); |
} |
@@ -1029,11 +1030,16 @@ |
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. |
@@ -1054,8 +1060,8 @@ |
object->Verify(); |
// All the interior pointers should be contained in the heap and |
- // have page regions covering intergenerational references should be |
- // marked dirty. |
+ // have their remembered set bits set if required as determined |
+ // by the visitor. |
int size = object->Size(); |
object->IterateBody(map->instance_type(), size, visitor); |
@@ -1628,7 +1634,7 @@ |
// 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::kHeaderSize) { |
+ if (size_in_bytes > ByteArray::kAlignedSize) { |
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); |
@@ -1901,14 +1907,15 @@ |
Page* p = it.next(); |
// Space below the relocation pointer is allocated. |
computed_size += |
- static_cast<int>(p->AllocationWatermark() - p->ObjectAreaStart()); |
+ static_cast<int>(p->mc_relocation_top - p->ObjectAreaStart()); |
if (it.has_next()) { |
- // Free the space at the top of the page. |
+ // 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). |
int extra_size = |
- static_cast<int>(p->ObjectAreaEnd() - p->AllocationWatermark()); |
+ static_cast<int>(p->ObjectAreaEnd() - p->mc_relocation_top); |
if (extra_size > 0) { |
- int wasted_bytes = free_list_.Free(p->AllocationWatermark(), |
- extra_size); |
+ int wasted_bytes = free_list_.Free(p->mc_relocation_top, extra_size); |
// The bytes we have just "freed" to add to the free list were |
// already accounted as available. |
accounting_stats_.WasteBytes(wasted_bytes); |
@@ -1956,10 +1963,7 @@ |
// Clean them up. |
do { |
- first->InvalidateWatermark(true); |
- first->SetAllocationWatermark(first->ObjectAreaStart()); |
- first->SetCachedAllocationWatermark(first->ObjectAreaStart()); |
- first->SetRegionMarks(Page::kAllRegionsCleanMarks); |
+ first->ClearRSet(); |
first = first->next_page(); |
} while (first != NULL); |
@@ -1999,7 +2003,6 @@ |
// 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()); |
@@ -2032,7 +2035,6 @@ |
int size_in_bytes = static_cast<int>(PageAllocationLimit(p) - |
p->ObjectAreaStart()); |
- p->SetAllocationWatermark(p->ObjectAreaStart()); |
Heap::CreateFillerObjectAt(p->ObjectAreaStart(), size_in_bytes); |
} |
} |
@@ -2064,7 +2066,6 @@ |
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; |
@@ -2099,15 +2100,7 @@ |
accounting_stats_.WasteBytes(wasted_bytes); |
if (!result->IsFailure()) { |
accounting_stats_.AllocateBytes(size_in_bytes); |
- |
- HeapObject* obj = HeapObject::cast(result); |
- Page* p = Page::FromAddress(obj->address()); |
- |
- if (obj->address() >= p->AllocationWatermark()) { |
- p->SetAllocationWatermark(obj->address() + size_in_bytes); |
- } |
- |
- return obj; |
+ return HeapObject::cast(result); |
} |
} |
@@ -2130,7 +2123,6 @@ |
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) { |
@@ -2141,7 +2133,6 @@ |
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. |
@@ -2161,7 +2152,6 @@ |
HeapObject* OldSpace::AllocateInNextPage(Page* current_page, |
int size_in_bytes) { |
ASSERT(current_page->next_page()->is_valid()); |
- current_page->next_page()->InvalidateWatermark(true); |
PutRestOfCurrentPageOnFreeList(current_page); |
SetAllocationInfo(&allocation_info_, current_page->next_page()); |
return AllocateLinearly(&allocation_info_, size_in_bytes); |
@@ -2306,12 +2296,160 @@ |
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 |
// ----------------------------------------------------------------------------- |
@@ -2361,7 +2499,6 @@ |
if (it.has_next()) { |
accounting_stats_.WasteBytes( |
static_cast<int>(page->ObjectAreaEnd() - page_top)); |
- page->SetAllocationWatermark(page_top); |
} |
} |
@@ -2391,14 +2528,7 @@ |
Object* result = free_list_.Allocate(); |
if (!result->IsFailure()) { |
accounting_stats_.AllocateBytes(size_in_bytes); |
- HeapObject* obj = HeapObject::cast(result); |
- Page* p = Page::FromAddress(obj->address()); |
- |
- if (obj->address() >= p->AllocationWatermark()) { |
- p->SetAllocationWatermark(obj->address() + size_in_bytes); |
- } |
- |
- return obj; |
+ return HeapObject::cast(result); |
} |
} |
@@ -2428,8 +2558,6 @@ |
ASSERT(current_page->next_page()->is_valid()); |
ASSERT(allocation_info_.top == PageAllocationLimit(current_page)); |
ASSERT_EQ(object_size_in_bytes_, size_in_bytes); |
- current_page->next_page()->InvalidateWatermark(true); |
- current_page->SetAllocationWatermark(allocation_info_.top); |
accounting_stats_.WasteBytes(page_extra_); |
SetAllocationInfo(&allocation_info_, current_page->next_page()); |
return AllocateLinearly(&allocation_info_, size_in_bytes); |
@@ -2442,12 +2570,51 @@ |
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 |
@@ -2626,7 +2793,8 @@ |
chunk->set_size(chunk_size); |
first_chunk_ = chunk; |
- // Initialize page header. |
+ // Set the object address and size in the page header and clear its |
+ // remembered set. |
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 |
@@ -2634,7 +2802,13 @@ |
// low order bit should already be clear. |
ASSERT((chunk_size & 0x1) == 0); |
page->SetIsLargeObjectPage(true); |
- page->SetRegionMarks(Page::kAllRegionsCleanMarks); |
+ 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); |
+ } |
+ |
return HeapObject::FromAddress(object_address); |
} |
@@ -2649,7 +2823,8 @@ |
Object* LargeObjectSpace::AllocateRawFixedArray(int size_in_bytes) { |
ASSERT(0 < size_in_bytes); |
- return AllocateRawInternal(size_in_bytes, |
+ int extra_rset_bytes = ExtraRSetBytesFor(size_in_bytes); |
+ return AllocateRawInternal(size_in_bytes + extra_rset_bytes, |
size_in_bytes, |
NOT_EXECUTABLE); |
} |
@@ -2676,62 +2851,60 @@ |
return Failure::Exception(); |
} |
-void LargeObjectSpace::IterateDirtyRegions(ObjectSlotCallback copy_object) { |
+ |
+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 can possibly contain pointers to |
- // the young generation. |
+ // 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()); |
- uint32_t marks = page->GetRegionMarks(); |
- uint32_t newmarks = Page::kAllRegionsCleanMarks; |
+ page->ClearRSet(); |
- 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(); |
+ // Clear the extra remembered set. |
+ int size = object->Size(); |
+ int extra_rset_bytes = ExtraRSetBytesFor(size); |
+ memset(object->address() + size, 0, extra_rset_bytes); |
+ } |
+ } |
+} |
- // 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; |
- } |
+void LargeObjectSpace::IterateRSet(ObjectSlotCallback copy_object_func) { |
+ ASSERT(Page::is_rset_in_use()); |
- 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); |
- } |
+ 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); |
- page->SetRegionMarks(newmarks); |
+ 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); |
+ } |
} |
} |
} |
@@ -2822,7 +2995,7 @@ |
} 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 IsRegionDirty. |
+ // needed for IsRSetSet. |
FixedArray* array = FixedArray::cast(object); |
for (int j = 0; j < array->length(); j++) { |
Object* element = array->get(j); |
@@ -2831,11 +3004,8 @@ |
ASSERT(Heap::Contains(element_object)); |
ASSERT(element_object->map()->IsMap()); |
if (Heap::InNewSpace(element_object)) { |
- Address array_addr = object->address(); |
- Address element_addr = array_addr + FixedArray::kHeaderSize + |
- j * kPointerSize; |
- |
- ASSERT(Page::FromAddress(array_addr)->IsRegionDirty(element_addr)); |
+ ASSERT(Page::IsRSetSet(object->address(), |
+ FixedArray::kHeaderSize + j * kPointerSize)); |
} |
} |
} |
@@ -2876,6 +3046,33 @@ |
} |
} |
} |
+ |
+ |
+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 |