| Index: src/spaces.h
|
| ===================================================================
|
| --- src/spaces.h (revision 4686)
|
| +++ src/spaces.h (working copy)
|
| @@ -45,47 +45,24 @@
|
| // The old generation is collected by a mark-sweep-compact collector.
|
| //
|
| // The semispaces of the young generation are contiguous. The old and map
|
| -// spaces consists of a list of pages. A page has a page header and an object
|
| -// area. A page size is deliberately chosen as 8K bytes.
|
| -// The first word of a page is an opaque page header that has the
|
| +// spaces consists of a list of pages. A page has a page header, a remembered
|
| +// set area, and an object area. A page size is deliberately chosen as 8K
|
| +// bytes. The first word of a page is an opaque page header that has the
|
| // address of the next page and its ownership information. The second word may
|
| -// have the allocation top address of this page. Heap objects are aligned to the
|
| -// pointer size.
|
| +// have the allocation top address of this page. The next 248 bytes are
|
| +// remembered sets. Heap objects are aligned to the pointer size (4 bytes). A
|
| +// remembered set bit corresponds to a pointer in the object area.
|
| //
|
| // There is a separate large object space for objects larger than
|
| // Page::kMaxHeapObjectSize, so that they do not have to move during
|
| -// collection. The large object space is paged. Pages in large object space
|
| -// may be larger than 8K.
|
| +// collection. The large object space is paged and uses the same remembered
|
| +// set implementation. Pages in large object space may be larger than 8K.
|
| //
|
| -// A card marking write barrier is used to keep track of intergenerational
|
| -// references. Old space pages are divided into regions of Page::kRegionSize
|
| -// size. Each region has a corresponding dirty bit in the page header which is
|
| -// set if the region might contain pointers to new space. For details about
|
| -// dirty bits encoding see comments in the Page::GetRegionNumberForAddress()
|
| -// method body.
|
| -//
|
| -// During scavenges and mark-sweep collections we iterate intergenerational
|
| -// pointers without decoding heap object maps so if the page belongs to old
|
| -// pointer space or large object space it is essential to guarantee that
|
| -// the page does not contain any garbage pointers to new space: every pointer
|
| -// aligned word which satisfies the Heap::InNewSpace() predicate must be a
|
| -// pointer to a live heap object in new space. Thus objects in old pointer
|
| -// and large object spaces should have a special layout (e.g. no bare integer
|
| -// fields). This requirement does not apply to map space which is iterated in
|
| -// a special fashion. However we still require pointer fields of dead maps to
|
| -// be cleaned.
|
| -//
|
| -// To enable lazy cleaning of old space pages we use a notion of allocation
|
| -// watermark. Every pointer under watermark is considered to be well formed.
|
| -// Page allocation watermark is not necessarily equal to page allocation top but
|
| -// all alive objects on page should reside under allocation watermark.
|
| -// During scavenge allocation watermark might be bumped and invalid pointers
|
| -// might appear below it. To avoid following them we store a valid watermark
|
| -// into special field in the page header and set a page WATERMARK_INVALIDATED
|
| -// flag. For details see comments in the Page::SetAllocationWatermark() method
|
| -// body.
|
| -//
|
| +// NOTE: The mark-compact collector rebuilds the remembered set after a
|
| +// collection. It reuses first a few words of the remembered set for
|
| +// bookkeeping relocation information.
|
|
|
| +
|
| // Some assertion macros used in the debugging mode.
|
|
|
| #define ASSERT_PAGE_ALIGNED(address) \
|
| @@ -114,13 +91,25 @@
|
|
|
| // -----------------------------------------------------------------------------
|
| // A page normally has 8K bytes. Large object pages may be larger. A page
|
| -// address is always aligned to the 8K page size.
|
| +// address is always aligned to the 8K page size. A page is divided into
|
| +// three areas: the first two words are used for bookkeeping, the next 248
|
| +// bytes are used as remembered set, and the rest of the page is the object
|
| +// area.
|
| //
|
| -// Each page starts with a header of Page::kPageHeaderSize size which contains
|
| -// bookkeeping data.
|
| +// Pointers are aligned to the pointer size (4), only 1 bit is needed
|
| +// for a pointer in the remembered set. Given an address, its remembered set
|
| +// bit position (offset from the start of the page) is calculated by dividing
|
| +// its page offset by 32. Therefore, the object area in a page starts at the
|
| +// 256th byte (8K/32). Bytes 0 to 255 do not need the remembered set, so that
|
| +// the first two words (64 bits) in a page can be used for other purposes.
|
| //
|
| +// On the 64-bit platform, we add an offset to the start of the remembered set,
|
| +// and pointers are aligned to 8-byte pointer size. This means that we need
|
| +// only 128 bytes for the RSet, and only get two bytes free in the RSet's RSet.
|
| +// For this reason we add an offset to get room for the Page data at the start.
|
| +//
|
| // The mark-compact collector transforms a map pointer into a page index and a
|
| -// page offset. The exact encoding is described in the comments for
|
| +// page offset. The excact encoding is described in the comments for
|
| // class MapWord in objects.h.
|
| //
|
| // The only way to get a page pointer is by calling factory methods:
|
| @@ -161,25 +150,18 @@
|
| // Return the end of allocation in this page. Undefined for unused pages.
|
| inline Address AllocationTop();
|
|
|
| - // Return the allocation watermark for the page.
|
| - // For old space pages it is guaranteed that the area under the watermark
|
| - // does not contain any garbage pointers to new space.
|
| - inline Address AllocationWatermark();
|
| -
|
| - // Return the allocation watermark offset from the beginning of the page.
|
| - inline uint32_t AllocationWatermarkOffset();
|
| -
|
| - inline void SetAllocationWatermark(Address allocation_watermark);
|
| -
|
| - inline void SetCachedAllocationWatermark(Address allocation_watermark);
|
| - inline Address CachedAllocationWatermark();
|
| -
|
| // Returns the start address of the object area in this page.
|
| Address ObjectAreaStart() { return address() + kObjectStartOffset; }
|
|
|
| // Returns the end address (exclusive) of the object area in this page.
|
| Address ObjectAreaEnd() { return address() + Page::kPageSize; }
|
|
|
| + // Returns the start address of the remembered set area.
|
| + Address RSetStart() { return address() + kRSetStartOffset; }
|
| +
|
| + // Returns the end address of the remembered set area (exclusive).
|
| + Address RSetEnd() { return address() + kRSetEndOffset; }
|
| +
|
| // Checks whether an address is page aligned.
|
| static bool IsAlignedToPageSize(Address a) {
|
| return 0 == (OffsetFrom(a) & kPageAlignmentMask);
|
| @@ -211,99 +193,74 @@
|
| }
|
|
|
| // ---------------------------------------------------------------------
|
| - // Card marking support
|
| + // Remembered set support
|
|
|
| - static const uint32_t kAllRegionsCleanMarks = 0x0;
|
| + // Clears remembered set in this page.
|
| + inline void ClearRSet();
|
|
|
| - inline uint32_t GetRegionMarks();
|
| - inline void SetRegionMarks(uint32_t dirty);
|
| + // Return the address of the remembered set word corresponding to an
|
| + // object address/offset pair, and the bit encoded as a single-bit
|
| + // mask in the output parameter 'bitmask'.
|
| + INLINE(static Address ComputeRSetBitPosition(Address address, int offset,
|
| + uint32_t* bitmask));
|
|
|
| - inline uint32_t GetRegionMaskForAddress(Address addr);
|
| - inline int GetRegionNumberForAddress(Address addr);
|
| + // Sets the corresponding remembered set bit for a given address.
|
| + INLINE(static void SetRSet(Address address, int offset));
|
|
|
| - inline void MarkRegionDirty(Address addr);
|
| - inline bool IsRegionDirty(Address addr);
|
| + // Clears the corresponding remembered set bit for a given address.
|
| + static inline void UnsetRSet(Address address, int offset);
|
|
|
| - inline void ClearRegionMarks(Address start,
|
| - Address end,
|
| - bool reaches_limit);
|
| + // Checks whether the remembered set bit for a given address is set.
|
| + static inline bool IsRSetSet(Address address, int offset);
|
|
|
| +#ifdef DEBUG
|
| + // Use a state to mark whether remembered set space can be used for other
|
| + // purposes.
|
| + enum RSetState { IN_USE, NOT_IN_USE };
|
| + static bool is_rset_in_use() { return rset_state_ == IN_USE; }
|
| + static void set_rset_state(RSetState state) { rset_state_ = state; }
|
| +#endif
|
| +
|
| // Page size in bytes. This must be a multiple of the OS page size.
|
| static const int kPageSize = 1 << kPageSizeBits;
|
|
|
| // Page size mask.
|
| static const intptr_t kPageAlignmentMask = (1 << kPageSizeBits) - 1;
|
|
|
| - static const int kPageHeaderSize = kPointerSize + kPointerSize + kIntSize +
|
| - kIntSize + kPointerSize;
|
| + // The offset of the remembered set in a page, in addition to the empty bytes
|
| + // formed as the remembered bits of the remembered set itself.
|
| +#ifdef V8_TARGET_ARCH_X64
|
| + static const int kRSetOffset = 4 * kPointerSize; // Room for four pointers.
|
| +#else
|
| + static const int kRSetOffset = 0;
|
| +#endif
|
| + // The end offset of the remembered set in a page
|
| + // (heaps are aligned to pointer size).
|
| + static const int kRSetEndOffset = kRSetOffset + kPageSize / kBitsPerPointer;
|
|
|
| // The start offset of the object area in a page.
|
| - static const int kObjectStartOffset = MAP_POINTER_ALIGN(kPageHeaderSize);
|
| + // This needs to be at least (bits per uint32_t) * kBitsPerPointer,
|
| + // to align start of rset to a uint32_t address.
|
| + static const int kObjectStartOffset = 256;
|
|
|
| + // The start offset of the used part of the remembered set in a page.
|
| + static const int kRSetStartOffset = kRSetOffset +
|
| + kObjectStartOffset / kBitsPerPointer;
|
| +
|
| // Object area size in bytes.
|
| static const int kObjectAreaSize = kPageSize - kObjectStartOffset;
|
|
|
| // Maximum object size that fits in a page.
|
| static const int kMaxHeapObjectSize = kObjectAreaSize;
|
|
|
| - static const int kDirtyFlagOffset = 2 * kPointerSize;
|
| - static const int kRegionSizeLog2 = 8;
|
| - static const int kRegionSize = 1 << kRegionSizeLog2;
|
| - static const intptr_t kRegionAlignmentMask = (kRegionSize - 1);
|
| -
|
| - STATIC_CHECK(kRegionSize == kPageSize / kBitsPerInt);
|
| -
|
| enum PageFlag {
|
| IS_NORMAL_PAGE = 1 << 0,
|
| - WAS_IN_USE_BEFORE_MC = 1 << 1,
|
| -
|
| - // Page allocation watermark was bumped by preallocation during scavenge.
|
| - // Correct watermark can be retrieved by CachedAllocationWatermark() method
|
| - WATERMARK_INVALIDATED = 1 << 2
|
| + WAS_IN_USE_BEFORE_MC = 1 << 1
|
| };
|
|
|
| - // To avoid an additional WATERMARK_INVALIDATED flag clearing pass during
|
| - // scavenge we just invalidate the watermark on each old space page after
|
| - // processing it. And then we flip the meaning of the WATERMARK_INVALIDATED
|
| - // flag at the beginning of the next scavenge and each page becomes marked as
|
| - // having a valid watermark.
|
| - //
|
| - // The following invariant must hold for pages in old pointer and map spaces:
|
| - // If page is in use then page is marked as having invalid watermark at
|
| - // the beginning and at the end of any GC.
|
| - //
|
| - // This invariant guarantees that after flipping flag meaning at the
|
| - // beginning of scavenge all pages in use will be marked as having valid
|
| - // watermark.
|
| - static inline void FlipMeaningOfInvalidatedWatermarkFlag();
|
| -
|
| - // Returns true if the page allocation watermark was not altered during
|
| - // scavenge.
|
| - inline bool IsWatermarkValid();
|
| -
|
| - inline void InvalidateWatermark(bool value);
|
| -
|
| inline bool GetPageFlag(PageFlag flag);
|
| inline void SetPageFlag(PageFlag flag, bool value);
|
| - inline void ClearPageFlags();
|
|
|
| - static const int kAllocationWatermarkOffsetShift = 3;
|
| - static const int kAllocationWatermarkOffsetBits = kPageSizeBits + 1;
|
| - static const uint32_t kAllocationWatermarkOffsetMask =
|
| - ((1 << kAllocationWatermarkOffsetBits) - 1) <<
|
| - kAllocationWatermarkOffsetShift;
|
| -
|
| - static const uint32_t kFlagsMask =
|
| - ((1 << kAllocationWatermarkOffsetShift) - 1);
|
| -
|
| - STATIC_CHECK(kBitsPerInt - kAllocationWatermarkOffsetShift >=
|
| - kAllocationWatermarkOffsetBits);
|
| -
|
| - // This field contains the meaning of the WATERMARK_INVALIDATED flag.
|
| - // Instead of clearing this flag from all pages we just flip
|
| - // its meaning at the beginning of a scavenge.
|
| - static intptr_t watermark_invalidated_mark_;
|
| -
|
| //---------------------------------------------------------------------------
|
| // Page header description.
|
| //
|
| @@ -322,24 +279,26 @@
|
| // second word *may* (if the page start and large object chunk start are
|
| // the same) contain the large object chunk size. In either case, the
|
| // low-order bit for large object pages will be cleared.
|
| - // For normal pages this word is used to store page flags and
|
| - // offset of allocation top.
|
| - intptr_t flags_;
|
| + // For normal pages this word is used to store various page flags.
|
| + int flags;
|
|
|
| - // This field contains dirty marks for regions covering the page. Only dirty
|
| - // regions might contain intergenerational references.
|
| - // Only 32 dirty marks are supported so for large object pages several regions
|
| - // might be mapped to a single dirty mark.
|
| - uint32_t dirty_regions_;
|
| + // The following fields may overlap with remembered set, they can only
|
| + // be used in the mark-compact collector when remembered set is not
|
| + // used.
|
|
|
| // The index of the page in its owner space.
|
| int mc_page_index;
|
|
|
| - // During mark-compact collections this field contains the forwarding address
|
| - // of the first live object in this page.
|
| - // During scavenge collection this field is used to store allocation watermark
|
| - // if it is altered during scavenge.
|
| + // The allocation pointer after relocating objects to this page.
|
| + Address mc_relocation_top;
|
| +
|
| + // The forwarding address of the first live object in this page.
|
| Address mc_first_forwarded;
|
| +
|
| +#ifdef DEBUG
|
| + private:
|
| + static RSetState rset_state_; // state of the remembered set
|
| +#endif
|
| };
|
|
|
|
|
| @@ -962,7 +921,8 @@
|
| // Checks whether page is currently in use by this space.
|
| bool IsUsed(Page* page);
|
|
|
| - void MarkAllPagesClean();
|
| + // Clears remembered sets of pages in this space.
|
| + void ClearRSet();
|
|
|
| // Prepares for a mark-compact GC.
|
| virtual void PrepareForMarkCompact(bool will_compact);
|
| @@ -976,11 +936,6 @@
|
| // The limit of allocation for a page in this space.
|
| virtual Address PageAllocationLimit(Page* page) = 0;
|
|
|
| - void FlushTopPageWatermark() {
|
| - AllocationTopPage()->SetCachedAllocationWatermark(top());
|
| - AllocationTopPage()->InvalidateWatermark(true);
|
| - }
|
| -
|
| // Current capacity without growing (Size() + Available() + Waste()).
|
| int Capacity() { return accounting_stats_.Capacity(); }
|
|
|
| @@ -1035,8 +990,7 @@
|
|
|
| // Writes relocation info to the top page.
|
| void MCWriteRelocationInfoToPage() {
|
| - TopPageOf(mc_forwarding_info_)->
|
| - SetAllocationWatermark(mc_forwarding_info_.top);
|
| + TopPageOf(mc_forwarding_info_)->mc_relocation_top = mc_forwarding_info_.top;
|
| }
|
|
|
| // Computes the offset of a given address in this space to the beginning
|
| @@ -1154,6 +1108,8 @@
|
| #ifdef DEBUG
|
| // Returns the number of total pages in this space.
|
| int CountTotalPages();
|
| +
|
| + void DoPrintRSet(const char* space_name);
|
| #endif
|
| private:
|
|
|
| @@ -1790,10 +1746,6 @@
|
| if (add_to_freelist) {
|
| int wasted_bytes = free_list_.Free(start, size_in_bytes);
|
| accounting_stats_.WasteBytes(wasted_bytes);
|
| - } else {
|
| -#ifdef DEBUG
|
| - MemoryAllocator::ZapBlock(start, size_in_bytes);
|
| -#endif
|
| }
|
| }
|
|
|
| @@ -1810,6 +1762,8 @@
|
| #ifdef DEBUG
|
| // Reports statistics for the space
|
| void ReportStatistics();
|
| + // Dump the remembered sets in the space to stdout.
|
| + void PrintRSet();
|
| #endif
|
|
|
| protected:
|
| @@ -1858,10 +1812,6 @@
|
| void Free(Address start, bool add_to_freelist) {
|
| if (add_to_freelist) {
|
| free_list_.Free(start);
|
| - } else {
|
| -#ifdef DEBUG
|
| - MemoryAllocator::ZapBlock(start, object_size_in_bytes_);
|
| -#endif
|
| }
|
| accounting_stats_.DeallocateBytes(object_size_in_bytes_);
|
| }
|
| @@ -1878,6 +1828,9 @@
|
| #ifdef DEBUG
|
| // Reports statistic info of the space
|
| void ReportStatistics();
|
| +
|
| + // Dump the remembered sets in the space to stdout.
|
| + void PrintRSet();
|
| #endif
|
|
|
| protected:
|
| @@ -1946,11 +1899,11 @@
|
| PageIterator it(this, PageIterator::ALL_PAGES);
|
| while (pages_left-- > 0) {
|
| ASSERT(it.has_next());
|
| - it.next()->SetRegionMarks(Page::kAllRegionsCleanMarks);
|
| + it.next()->ClearRSet();
|
| }
|
| ASSERT(it.has_next());
|
| Page* top_page = it.next();
|
| - top_page->SetRegionMarks(Page::kAllRegionsCleanMarks);
|
| + top_page->ClearRSet();
|
| ASSERT(top_page->is_valid());
|
|
|
| int offset = live_maps % kMapsPerPage * Map::kSize;
|
| @@ -2041,8 +1994,9 @@
|
| public:
|
| // Allocates a new LargeObjectChunk that contains a large object page
|
| // (Page::kPageSize aligned) that has at least size_in_bytes (for a large
|
| - // object) bytes after the object area start of that page.
|
| - // The allocated chunk size is set in the output parameter chunk_size.
|
| + // object and possibly extra remembered set words) bytes after the object
|
| + // area start of that page. The allocated chunk size is set in the output
|
| + // parameter chunk_size.
|
| static LargeObjectChunk* New(int size_in_bytes,
|
| size_t* chunk_size,
|
| Executability executable);
|
| @@ -2065,12 +2019,16 @@
|
| // Returns the object in this chunk.
|
| inline HeapObject* GetObject();
|
|
|
| - // Given a requested size returns the physical size of a chunk to be
|
| - // allocated.
|
| + // Given a requested size (including any extra remembered set words),
|
| + // returns the physical size of a chunk to be allocated.
|
| static int ChunkSizeFor(int size_in_bytes);
|
|
|
| - // Given a chunk size, returns the object size it can accommodate. Used by
|
| - // LargeObjectSpace::Available.
|
| + // Given a chunk size, returns the object size it can accommodate (not
|
| + // including any extra remembered set words). Used by
|
| + // LargeObjectSpace::Available. Note that this can overestimate the size
|
| + // of object that will fit in a chunk---if the object requires extra
|
| + // remembered set words (eg, for large fixed arrays), the actual object
|
| + // size for the chunk will be smaller than reported by this function.
|
| static int ObjectSizeFor(int chunk_size) {
|
| if (chunk_size <= (Page::kPageSize + Page::kObjectStartOffset)) return 0;
|
| return chunk_size - Page::kPageSize - Page::kObjectStartOffset;
|
| @@ -2106,7 +2064,8 @@
|
| // Allocates a large FixedArray.
|
| Object* AllocateRawFixedArray(int size_in_bytes);
|
|
|
| - // Available bytes for objects in this space.
|
| + // Available bytes for objects in this space, not including any extra
|
| + // remembered set words.
|
| int Available() {
|
| return LargeObjectChunk::ObjectSizeFor(MemoryAllocator::Available());
|
| }
|
| @@ -2124,9 +2083,12 @@
|
| // space, may be slow.
|
| Object* FindObject(Address a);
|
|
|
| - // Iterates objects covered by dirty regions.
|
| - void IterateDirtyRegions(ObjectSlotCallback func);
|
| + // Clears remembered sets.
|
| + void ClearRSet();
|
|
|
| + // Iterates objects whose remembered set bits are set.
|
| + void IterateRSet(ObjectSlotCallback func);
|
| +
|
| // Frees unmarked objects.
|
| void FreeUnmarkedObjects();
|
|
|
| @@ -2152,6 +2114,8 @@
|
| virtual void Print();
|
| void ReportStatistics();
|
| void CollectCodeStatistics();
|
| + // Dump the remembered sets in the space to stdout.
|
| + void PrintRSet();
|
| #endif
|
| // Checks whether an address is in the object area in this space. It
|
| // iterates all objects in the space. May be slow.
|
| @@ -2170,6 +2134,10 @@
|
| int object_size,
|
| Executability executable);
|
|
|
| + // Returns the number of extra bytes (rounded up to the nearest full word)
|
| + // required for extra_object_bytes of extra pointers (in bytes).
|
| + static inline int ExtraRSetBytesFor(int extra_object_bytes);
|
| +
|
| friend class LargeObjectIterator;
|
|
|
| public:
|
|
|