| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_HEAP_SPACES_H_ | 5 #ifndef V8_HEAP_SPACES_H_ |
| 6 #define V8_HEAP_SPACES_H_ | 6 #define V8_HEAP_SPACES_H_ |
| 7 | 7 |
| 8 #include "src/allocation.h" | 8 #include "src/allocation.h" |
| 9 #include "src/base/atomicops.h" | 9 #include "src/base/atomicops.h" |
| 10 #include "src/base/bits.h" | 10 #include "src/base/bits.h" |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 // There is a separate large object space for objects larger than | 36 // There is a separate large object space for objects larger than |
| 37 // Page::kMaxHeapObjectSize, so that they do not have to move during | 37 // Page::kMaxHeapObjectSize, so that they do not have to move during |
| 38 // collection. The large object space is paged. Pages in large object space | 38 // collection. The large object space is paged. Pages in large object space |
| 39 // may be larger than the page size. | 39 // may be larger than the page size. |
| 40 // | 40 // |
| 41 // A store-buffer based write barrier is used to keep track of intergenerational | 41 // A store-buffer based write barrier is used to keep track of intergenerational |
| 42 // references. See heap/store-buffer.h. | 42 // references. See heap/store-buffer.h. |
| 43 // | 43 // |
| 44 // During scavenges and mark-sweep collections we sometimes (after a store | 44 // During scavenges and mark-sweep collections we sometimes (after a store |
| 45 // buffer overflow) iterate intergenerational pointers without decoding heap | 45 // buffer overflow) iterate intergenerational pointers without decoding heap |
| 46 // object maps so if the page belongs to old space or large object space | 46 // object maps so if the page belongs to old pointer space or large object |
| 47 // it is essential to guarantee that the page does not contain any | 47 // space it is essential to guarantee that the page does not contain any |
| 48 // garbage pointers to new space: every pointer aligned word which satisfies | 48 // garbage pointers to new space: every pointer aligned word which satisfies |
| 49 // the Heap::InNewSpace() predicate must be a pointer to a live heap object in | 49 // the Heap::InNewSpace() predicate must be a pointer to a live heap object in |
| 50 // new space. Thus objects in old space and large object spaces should have a | 50 // new space. Thus objects in old pointer and large object spaces should have a |
| 51 // special layout (e.g. no bare integer fields). This requirement does not | 51 // special layout (e.g. no bare integer fields). This requirement does not |
| 52 // apply to map space which is iterated in a special fashion. However we still | 52 // apply to map space which is iterated in a special fashion. However we still |
| 53 // require pointer fields of dead maps to be cleaned. | 53 // require pointer fields of dead maps to be cleaned. |
| 54 // | 54 // |
| 55 // To enable lazy cleaning of old space pages we can mark chunks of the page | 55 // To enable lazy cleaning of old space pages we can mark chunks of the page |
| 56 // as being garbage. Garbage sections are marked with a special map. These | 56 // as being garbage. Garbage sections are marked with a special map. These |
| 57 // sections are skipped when scanning the page, even if we are otherwise | 57 // sections are skipped when scanning the page, even if we are otherwise |
| 58 // scanning without regard for object boundaries. Garbage sections are chained | 58 // scanning without regard for object boundaries. Garbage sections are chained |
| 59 // together to form a free list after a GC. Garbage sections created outside | 59 // together to form a free list after a GC. Garbage sections created outside |
| 60 // of GCs by object trunctation etc. may not be in the free list chain. Very | 60 // of GCs by object trunctation etc. may not be in the free list chain. Very |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 class MemoryAllocator; | 95 class MemoryAllocator; |
| 96 class AllocationInfo; | 96 class AllocationInfo; |
| 97 class Space; | 97 class Space; |
| 98 class FreeList; | 98 class FreeList; |
| 99 class MemoryChunk; | 99 class MemoryChunk; |
| 100 | 100 |
| 101 class MarkBit { | 101 class MarkBit { |
| 102 public: | 102 public: |
| 103 typedef uint32_t CellType; | 103 typedef uint32_t CellType; |
| 104 | 104 |
| 105 inline MarkBit(CellType* cell, CellType mask) : cell_(cell), mask_(mask) {} | 105 inline MarkBit(CellType* cell, CellType mask, bool data_only) |
| 106 : cell_(cell), mask_(mask), data_only_(data_only) {} |
| 106 | 107 |
| 107 inline CellType* cell() { return cell_; } | 108 inline CellType* cell() { return cell_; } |
| 108 inline CellType mask() { return mask_; } | 109 inline CellType mask() { return mask_; } |
| 109 | 110 |
| 110 #ifdef DEBUG | 111 #ifdef DEBUG |
| 111 bool operator==(const MarkBit& other) { | 112 bool operator==(const MarkBit& other) { |
| 112 return cell_ == other.cell_ && mask_ == other.mask_; | 113 return cell_ == other.cell_ && mask_ == other.mask_; |
| 113 } | 114 } |
| 114 #endif | 115 #endif |
| 115 | 116 |
| 116 inline void Set() { *cell_ |= mask_; } | 117 inline void Set() { *cell_ |= mask_; } |
| 117 inline bool Get() { return (*cell_ & mask_) != 0; } | 118 inline bool Get() { return (*cell_ & mask_) != 0; } |
| 118 inline void Clear() { *cell_ &= ~mask_; } | 119 inline void Clear() { *cell_ &= ~mask_; } |
| 119 | 120 |
| 121 inline bool data_only() { return data_only_; } |
| 120 | 122 |
| 121 inline MarkBit Next() { | 123 inline MarkBit Next() { |
| 122 CellType new_mask = mask_ << 1; | 124 CellType new_mask = mask_ << 1; |
| 123 if (new_mask == 0) { | 125 if (new_mask == 0) { |
| 124 return MarkBit(cell_ + 1, 1); | 126 return MarkBit(cell_ + 1, 1, data_only_); |
| 125 } else { | 127 } else { |
| 126 return MarkBit(cell_, new_mask); | 128 return MarkBit(cell_, new_mask, data_only_); |
| 127 } | 129 } |
| 128 } | 130 } |
| 129 | 131 |
| 130 private: | 132 private: |
| 131 CellType* cell_; | 133 CellType* cell_; |
| 132 CellType mask_; | 134 CellType mask_; |
| 135 // This boolean indicates that the object is in a data-only space with no |
| 136 // pointers. This enables some optimizations when marking. |
| 137 // It is expected that this field is inlined and turned into control flow |
| 138 // at the place where the MarkBit object is created. |
| 139 bool data_only_; |
| 133 }; | 140 }; |
| 134 | 141 |
| 135 | 142 |
| 136 // Bitmap is a sequence of cells each containing fixed number of bits. | 143 // Bitmap is a sequence of cells each containing fixed number of bits. |
| 137 class Bitmap { | 144 class Bitmap { |
| 138 public: | 145 public: |
| 139 static const uint32_t kBitsPerCell = 32; | 146 static const uint32_t kBitsPerCell = 32; |
| 140 static const uint32_t kBitsPerCellLog2 = 5; | 147 static const uint32_t kBitsPerCellLog2 = 5; |
| 141 static const uint32_t kBitIndexMask = kBitsPerCell - 1; | 148 static const uint32_t kBitIndexMask = kBitsPerCell - 1; |
| 142 static const uint32_t kBytesPerCell = kBitsPerCell / kBitsPerByte; | 149 static const uint32_t kBytesPerCell = kBitsPerCell / kBitsPerByte; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 173 INLINE(MarkBit::CellType* cells()) { | 180 INLINE(MarkBit::CellType* cells()) { |
| 174 return reinterpret_cast<MarkBit::CellType*>(this); | 181 return reinterpret_cast<MarkBit::CellType*>(this); |
| 175 } | 182 } |
| 176 | 183 |
| 177 INLINE(Address address()) { return reinterpret_cast<Address>(this); } | 184 INLINE(Address address()) { return reinterpret_cast<Address>(this); } |
| 178 | 185 |
| 179 INLINE(static Bitmap* FromAddress(Address addr)) { | 186 INLINE(static Bitmap* FromAddress(Address addr)) { |
| 180 return reinterpret_cast<Bitmap*>(addr); | 187 return reinterpret_cast<Bitmap*>(addr); |
| 181 } | 188 } |
| 182 | 189 |
| 183 inline MarkBit MarkBitFromIndex(uint32_t index) { | 190 inline MarkBit MarkBitFromIndex(uint32_t index, bool data_only = false) { |
| 184 MarkBit::CellType mask = 1 << (index & kBitIndexMask); | 191 MarkBit::CellType mask = 1 << (index & kBitIndexMask); |
| 185 MarkBit::CellType* cell = this->cells() + (index >> kBitsPerCellLog2); | 192 MarkBit::CellType* cell = this->cells() + (index >> kBitsPerCellLog2); |
| 186 return MarkBit(cell, mask); | 193 return MarkBit(cell, mask, data_only); |
| 187 } | 194 } |
| 188 | 195 |
| 189 static inline void Clear(MemoryChunk* chunk); | 196 static inline void Clear(MemoryChunk* chunk); |
| 190 | 197 |
| 191 static void PrintWord(uint32_t word, uint32_t himask = 0) { | 198 static void PrintWord(uint32_t word, uint32_t himask = 0) { |
| 192 for (uint32_t mask = 1; mask != 0; mask <<= 1) { | 199 for (uint32_t mask = 1; mask != 0; mask <<= 1) { |
| 193 if ((mask & himask) != 0) PrintF("["); | 200 if ((mask & himask) != 0) PrintF("["); |
| 194 PrintF((mask & word) ? "1" : "0"); | 201 PrintF((mask & word) ? "1" : "0"); |
| 195 if ((mask & himask) != 0) PrintF("]"); | 202 if ((mask & himask) != 0) PrintF("]"); |
| 196 } | 203 } |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 | 363 |
| 357 enum MemoryChunkFlags { | 364 enum MemoryChunkFlags { |
| 358 IS_EXECUTABLE, | 365 IS_EXECUTABLE, |
| 359 ABOUT_TO_BE_FREED, | 366 ABOUT_TO_BE_FREED, |
| 360 POINTERS_TO_HERE_ARE_INTERESTING, | 367 POINTERS_TO_HERE_ARE_INTERESTING, |
| 361 POINTERS_FROM_HERE_ARE_INTERESTING, | 368 POINTERS_FROM_HERE_ARE_INTERESTING, |
| 362 SCAN_ON_SCAVENGE, | 369 SCAN_ON_SCAVENGE, |
| 363 IN_FROM_SPACE, // Mutually exclusive with IN_TO_SPACE. | 370 IN_FROM_SPACE, // Mutually exclusive with IN_TO_SPACE. |
| 364 IN_TO_SPACE, // All pages in new space has one of these two set. | 371 IN_TO_SPACE, // All pages in new space has one of these two set. |
| 365 NEW_SPACE_BELOW_AGE_MARK, | 372 NEW_SPACE_BELOW_AGE_MARK, |
| 373 CONTAINS_ONLY_DATA, |
| 366 EVACUATION_CANDIDATE, | 374 EVACUATION_CANDIDATE, |
| 367 RESCAN_ON_EVACUATION, | 375 RESCAN_ON_EVACUATION, |
| 368 NEVER_EVACUATE, // May contain immortal immutables. | 376 NEVER_EVACUATE, // May contain immortal immutables. |
| 369 | 377 |
| 370 // WAS_SWEPT indicates that marking bits have been cleared by the sweeper, | 378 // WAS_SWEPT indicates that marking bits have been cleared by the sweeper, |
| 371 // otherwise marking bits are still intact. | 379 // otherwise marking bits are still intact. |
| 372 WAS_SWEPT, | 380 WAS_SWEPT, |
| 373 | 381 |
| 374 // Large objects can have a progress bar in their page header. These object | 382 // Large objects can have a progress bar in their page header. These object |
| 375 // are scanned in increments and will be kept black while being scanned. | 383 // are scanned in increments and will be kept black while being scanned. |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 | 558 |
| 551 void SetArea(Address area_start, Address area_end) { | 559 void SetArea(Address area_start, Address area_end) { |
| 552 area_start_ = area_start; | 560 area_start_ = area_start; |
| 553 area_end_ = area_end; | 561 area_end_ = area_end; |
| 554 } | 562 } |
| 555 | 563 |
| 556 Executability executable() { | 564 Executability executable() { |
| 557 return IsFlagSet(IS_EXECUTABLE) ? EXECUTABLE : NOT_EXECUTABLE; | 565 return IsFlagSet(IS_EXECUTABLE) ? EXECUTABLE : NOT_EXECUTABLE; |
| 558 } | 566 } |
| 559 | 567 |
| 568 bool ContainsOnlyData() { return IsFlagSet(CONTAINS_ONLY_DATA); } |
| 569 |
| 560 bool InNewSpace() { | 570 bool InNewSpace() { |
| 561 return (flags_ & ((1 << IN_FROM_SPACE) | (1 << IN_TO_SPACE))) != 0; | 571 return (flags_ & ((1 << IN_FROM_SPACE) | (1 << IN_TO_SPACE))) != 0; |
| 562 } | 572 } |
| 563 | 573 |
| 564 bool InToSpace() { return IsFlagSet(IN_TO_SPACE); } | 574 bool InToSpace() { return IsFlagSet(IN_TO_SPACE); } |
| 565 | 575 |
| 566 bool InFromSpace() { return IsFlagSet(IN_FROM_SPACE); } | 576 bool InFromSpace() { return IsFlagSet(IN_FROM_SPACE); } |
| 567 | 577 |
| 568 // --------------------------------------------------------------------- | 578 // --------------------------------------------------------------------- |
| 569 // Markbits support | 579 // Markbits support |
| (...skipping 2009 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2579 MUST_USE_RESULT AllocationResult SlowAllocateRaw(int size_in_bytes); | 2589 MUST_USE_RESULT AllocationResult SlowAllocateRaw(int size_in_bytes); |
| 2580 | 2590 |
| 2581 friend class SemiSpaceIterator; | 2591 friend class SemiSpaceIterator; |
| 2582 | 2592 |
| 2583 public: | 2593 public: |
| 2584 TRACK_MEMORY("NewSpace") | 2594 TRACK_MEMORY("NewSpace") |
| 2585 }; | 2595 }; |
| 2586 | 2596 |
| 2587 | 2597 |
| 2588 // ----------------------------------------------------------------------------- | 2598 // ----------------------------------------------------------------------------- |
| 2589 // Old object space (includes the old space of objects and code space) | 2599 // Old object space (excluding map objects) |
| 2590 | 2600 |
| 2591 class OldSpace : public PagedSpace { | 2601 class OldSpace : public PagedSpace { |
| 2592 public: | 2602 public: |
| 2593 // Creates an old space object with a given maximum capacity. | 2603 // Creates an old space object with a given maximum capacity. |
| 2594 // The constructor does not allocate pages from OS. | 2604 // The constructor does not allocate pages from OS. |
| 2595 OldSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id, | 2605 OldSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id, |
| 2596 Executability executable) | 2606 Executability executable) |
| 2597 : PagedSpace(heap, max_capacity, id, executable) {} | 2607 : PagedSpace(heap, max_capacity, id, executable) {} |
| 2598 | 2608 |
| 2599 public: | 2609 public: |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2788 | 2798 |
| 2789 // Iterates over the chunks (pages and large object pages) that can contain | 2799 // Iterates over the chunks (pages and large object pages) that can contain |
| 2790 // pointers to new space. | 2800 // pointers to new space. |
| 2791 class PointerChunkIterator BASE_EMBEDDED { | 2801 class PointerChunkIterator BASE_EMBEDDED { |
| 2792 public: | 2802 public: |
| 2793 inline explicit PointerChunkIterator(Heap* heap); | 2803 inline explicit PointerChunkIterator(Heap* heap); |
| 2794 | 2804 |
| 2795 // Return NULL when the iterator is done. | 2805 // Return NULL when the iterator is done. |
| 2796 MemoryChunk* next() { | 2806 MemoryChunk* next() { |
| 2797 switch (state_) { | 2807 switch (state_) { |
| 2798 case kOldSpaceState: { | 2808 case kOldPointerState: { |
| 2799 if (old_pointer_iterator_.has_next()) { | 2809 if (old_pointer_iterator_.has_next()) { |
| 2800 return old_pointer_iterator_.next(); | 2810 return old_pointer_iterator_.next(); |
| 2801 } | 2811 } |
| 2802 state_ = kMapState; | 2812 state_ = kMapState; |
| 2803 // Fall through. | 2813 // Fall through. |
| 2804 } | 2814 } |
| 2805 case kMapState: { | 2815 case kMapState: { |
| 2806 if (map_iterator_.has_next()) { | 2816 if (map_iterator_.has_next()) { |
| 2807 return map_iterator_.next(); | 2817 return map_iterator_.next(); |
| 2808 } | 2818 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2827 return NULL; | 2837 return NULL; |
| 2828 default: | 2838 default: |
| 2829 break; | 2839 break; |
| 2830 } | 2840 } |
| 2831 UNREACHABLE(); | 2841 UNREACHABLE(); |
| 2832 return NULL; | 2842 return NULL; |
| 2833 } | 2843 } |
| 2834 | 2844 |
| 2835 | 2845 |
| 2836 private: | 2846 private: |
| 2837 enum State { kOldSpaceState, kMapState, kLargeObjectState, kFinishedState }; | 2847 enum State { kOldPointerState, kMapState, kLargeObjectState, kFinishedState }; |
| 2838 State state_; | 2848 State state_; |
| 2839 PageIterator old_pointer_iterator_; | 2849 PageIterator old_pointer_iterator_; |
| 2840 PageIterator map_iterator_; | 2850 PageIterator map_iterator_; |
| 2841 LargeObjectIterator lo_iterator_; | 2851 LargeObjectIterator lo_iterator_; |
| 2842 }; | 2852 }; |
| 2843 | 2853 |
| 2844 | 2854 |
| 2845 #ifdef DEBUG | 2855 #ifdef DEBUG |
| 2846 struct CommentStatistic { | 2856 struct CommentStatistic { |
| 2847 const char* comment; | 2857 const char* comment; |
| 2848 int size; | 2858 int size; |
| 2849 int count; | 2859 int count; |
| 2850 void Clear() { | 2860 void Clear() { |
| 2851 comment = NULL; | 2861 comment = NULL; |
| 2852 size = 0; | 2862 size = 0; |
| 2853 count = 0; | 2863 count = 0; |
| 2854 } | 2864 } |
| 2855 // Must be small, since an iteration is used for lookup. | 2865 // Must be small, since an iteration is used for lookup. |
| 2856 static const int kMaxComments = 64; | 2866 static const int kMaxComments = 64; |
| 2857 }; | 2867 }; |
| 2858 #endif | 2868 #endif |
| 2859 } | 2869 } |
| 2860 } // namespace v8::internal | 2870 } // namespace v8::internal |
| 2861 | 2871 |
| 2862 #endif // V8_HEAP_SPACES_H_ | 2872 #endif // V8_HEAP_SPACES_H_ |
| OLD | NEW |