Index: src/spaces-inl.h |
diff --git a/src/spaces-inl.h b/src/spaces-inl.h |
index 66894c4f1c1a9511b3414aa73ca1c7c2fa167a56..13283c2b43747c74a21051abb103ffdd05ad7efb 100644 |
--- a/src/spaces-inl.h |
+++ b/src/spaces-inl.h |
@@ -66,99 +66,172 @@ Address Page::AllocationTop() { |
} |
-void Page::ClearRSet() { |
- // This method can be called in all rset states. |
- memset(RSetStart(), 0, kRSetEndOffset - kRSetStartOffset); |
-} |
- |
- |
-// Given a 32-bit address, separate its bits into: |
-// | page address | words (6) | bit offset (5) | pointer alignment (2) | |
-// The address of the rset word containing the bit for this word is computed as: |
-// page_address + words * 4 |
-// For a 64-bit address, if it is: |
-// | page address | words(5) | bit offset(5) | pointer alignment (3) | |
-// The address of the rset word containing the bit for this word is computed as: |
-// page_address + words * 4 + kRSetOffset. |
-// The rset is accessed as 32-bit words, and bit offsets in a 32-bit word, |
-// even on the X64 architecture. |
- |
-Address Page::ComputeRSetBitPosition(Address address, int offset, |
- uint32_t* bitmask) { |
- ASSERT(Page::is_rset_in_use()); |
- |
- Page* page = Page::FromAddress(address); |
- uint32_t bit_offset = ArithmeticShiftRight(page->Offset(address) + offset, |
- kPointerSizeLog2); |
- *bitmask = 1 << (bit_offset % kBitsPerInt); |
- |
- Address rset_address = |
- page->address() + kRSetOffset + (bit_offset / kBitsPerInt) * kIntSize; |
- // The remembered set address is either in the normal remembered set range |
- // of a page or else we have a large object page. |
- ASSERT((page->RSetStart() <= rset_address && rset_address < page->RSetEnd()) |
- || page->IsLargeObjectPage()); |
- |
- if (rset_address >= page->RSetEnd()) { |
- // We have a large object page, and the remembered set address is actually |
- // past the end of the object. |
- |
- // The first part of the remembered set is still located at the start of |
- // the page, but anything after kRSetEndOffset must be relocated to after |
- // the large object, i.e. after |
- // (page->ObjectAreaStart() + object size) |
- // We do that by adding the difference between the normal RSet's end and |
- // the object's end. |
- ASSERT(HeapObject::FromAddress(address)->IsFixedArray()); |
- int fixedarray_length = |
- FixedArray::SizeFor(Memory::int_at(page->ObjectAreaStart() |
- + Array::kLengthOffset)); |
- rset_address += kObjectStartOffset - kRSetEndOffset + fixedarray_length; |
+Address Page::AllocationWatermark() { |
+ PagedSpace* owner = MemoryAllocator::PageOwner(this); |
+ if (this == owner->AllocationTopPage()) { |
+ return owner->top(); |
} |
- return rset_address; |
+ return address() + AllocationWatermarkOffset(); |
} |
-void Page::SetRSet(Address address, int offset) { |
- uint32_t bitmask = 0; |
- Address rset_address = ComputeRSetBitPosition(address, offset, &bitmask); |
- Memory::uint32_at(rset_address) |= bitmask; |
+uint32_t Page::AllocationWatermarkOffset() { |
+ return (flags_ & kAllocationWatermarkOffsetMask) >> |
+ kAllocationWatermarkOffsetShift; |
+} |
+ |
- ASSERT(IsRSetSet(address, offset)); |
+void Page::SetAllocationWatermark(Address allocation_watermark) { |
+ if ((Heap::gc_state() == Heap::SCAVENGE) && IsWatermarkValid()) { |
+ // When iterating intergenerational references during scavenge |
+ // we might decide to promote an encountered young object. |
+ // We will allocate a space for such an object and put it |
+ // into the promotion queue to process it later. |
+ // If space for object was allocated somewhere beyond allocation |
+ // watermark this might cause garbage pointers to appear under allocation |
+ // watermark. To avoid visiting them during dirty regions iteration |
+ // which might be still in progress we store a valid allocation watermark |
+ // value and mark this page as having an invalid watermark. |
+ SetCachedAllocationWatermark(AllocationWatermark()); |
+ InvalidateWatermark(true); |
+ } |
+ |
+ flags_ = (flags_ & kFlagsMask) | |
+ Offset(allocation_watermark) << kAllocationWatermarkOffsetShift; |
+ ASSERT(AllocationWatermarkOffset() |
+ == static_cast<uint32_t>(Offset(allocation_watermark))); |
} |
-// Clears the corresponding remembered set bit for a given address. |
-void Page::UnsetRSet(Address address, int offset) { |
- uint32_t bitmask = 0; |
- Address rset_address = ComputeRSetBitPosition(address, offset, &bitmask); |
- Memory::uint32_at(rset_address) &= ~bitmask; |
+void Page::SetCachedAllocationWatermark(Address allocation_watermark) { |
+ mc_first_forwarded = allocation_watermark; |
+} |
+ |
+ |
+Address Page::CachedAllocationWatermark() { |
+ return mc_first_forwarded; |
+} |
+ |
+ |
+uint32_t Page::GetRegionMarks() { |
+ return dirty_regions_; |
+} |
+ |
- ASSERT(!IsRSetSet(address, offset)); |
+void Page::SetRegionMarks(uint32_t marks) { |
+ dirty_regions_ = marks; |
} |
-bool Page::IsRSetSet(Address address, int offset) { |
+int Page::GetRegionNumberForAddress(Address addr) { |
+ // Each page is divided into 256 byte regions. Each region has a corresponding |
+ // dirty mark bit in the page header. Region can contain intergenerational |
+ // references iff its dirty mark is set. |
+ // A normal 8K page contains exactly 32 regions so all region marks fit |
+ // into 32-bit integer field. To calculate a region number we just divide |
+ // offset inside page by region size. |
+ // A large page can contain more then 32 regions. But we want to avoid |
+ // additional write barrier code for distinguishing between large and normal |
+ // pages so we just ignore the fact that addr points into a large page and |
+ // calculate region number as if addr pointed into a normal 8K page. This way |
+ // we get a region number modulo 32 so for large pages several regions might |
+ // be mapped to a single dirty mark. |
+ ASSERT_PAGE_ALIGNED(this->address()); |
+ STATIC_ASSERT((kPageAlignmentMask >> kRegionSizeLog2) < kBitsPerInt); |
+ |
+ // We are using masking with kPageAlignmentMask instead of Page::Offset() |
+ // to get an offset to the beginning of 8K page containing addr not to the |
+ // beginning of actual page which can be bigger then 8K. |
+ return (OffsetFrom(addr) & kPageAlignmentMask) >> kRegionSizeLog2; |
+} |
+ |
+ |
+uint32_t Page::GetRegionMaskForAddress(Address addr) { |
+ return 1 << GetRegionNumberForAddress(addr); |
+} |
+ |
+ |
+void Page::MarkRegionDirty(Address address) { |
+ SetRegionMarks(GetRegionMarks() | GetRegionMaskForAddress(address)); |
+} |
+ |
+ |
+bool Page::IsRegionDirty(Address address) { |
+ return GetRegionMarks() & GetRegionMaskForAddress(address); |
+} |
+ |
+ |
+void Page::ClearRegionMarks(Address start, Address end, bool reaches_limit) { |
+ int rstart = GetRegionNumberForAddress(start); |
+ int rend = GetRegionNumberForAddress(end); |
+ |
+ if (reaches_limit) { |
+ end += 1; |
+ } |
+ |
+ if ((rend - rstart) == 0) { |
+ return; |
+ } |
+ |
uint32_t bitmask = 0; |
- Address rset_address = ComputeRSetBitPosition(address, offset, &bitmask); |
- return (Memory::uint32_at(rset_address) & bitmask) != 0; |
+ |
+ if ((OffsetFrom(start) & kRegionAlignmentMask) == 0 |
+ || (start == ObjectAreaStart())) { |
+ // First region is fully covered |
+ bitmask = 1 << rstart; |
+ } |
+ |
+ while (++rstart < rend) { |
+ bitmask |= 1 << rstart; |
+ } |
+ |
+ if (bitmask) { |
+ SetRegionMarks(GetRegionMarks() & ~bitmask); |
+ } |
+} |
+ |
+ |
+void Page::FlipMeaningOfInvalidatedWatermarkFlag() { |
+ watermark_invalidated_mark_ ^= WATERMARK_INVALIDATED; |
+} |
+ |
+ |
+bool Page::IsWatermarkValid() { |
+ return (flags_ & WATERMARK_INVALIDATED) != watermark_invalidated_mark_; |
+} |
+ |
+ |
+void Page::InvalidateWatermark(bool value) { |
+ if (value) { |
+ flags_ = (flags_ & ~WATERMARK_INVALIDATED) | watermark_invalidated_mark_; |
+ } else { |
+ flags_ = (flags_ & ~WATERMARK_INVALIDATED) | |
+ (watermark_invalidated_mark_ ^ WATERMARK_INVALIDATED); |
+ } |
+ |
+ ASSERT(IsWatermarkValid() == !value); |
} |
bool Page::GetPageFlag(PageFlag flag) { |
- return (flags & flag) != 0; |
+ return (flags_ & flag) != 0; |
} |
void Page::SetPageFlag(PageFlag flag, bool value) { |
if (value) { |
- flags |= flag; |
+ flags_ |= flag; |
} else { |
- flags &= ~flag; |
+ flags_ &= ~flag; |
} |
} |
+void Page::ClearPageFlags() { |
+ flags_ = 0; |
+} |
+ |
+ |
bool Page::WasInUseBeforeMC() { |
return GetPageFlag(WAS_IN_USE_BEFORE_MC); |
} |
@@ -343,14 +416,6 @@ HeapObject* LargeObjectChunk::GetObject() { |
// ----------------------------------------------------------------------------- |
// LargeObjectSpace |
-int LargeObjectSpace::ExtraRSetBytesFor(int object_size) { |
- int extra_rset_bits = |
- RoundUp((object_size - Page::kObjectAreaSize) / kPointerSize, |
- kBitsPerInt); |
- return extra_rset_bits / kBitsPerByte; |
-} |
- |
- |
Object* NewSpace::AllocateRawInternal(int size_in_bytes, |
AllocationInfo* alloc_info) { |
Address new_top = alloc_info->top + size_in_bytes; |