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