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 pointer space or large object | 46 // object maps so if the page belongs to old space or large object space |
47 // space it is essential to guarantee that the page does not contain any | 47 // 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 pointer and large object spaces should have a | 50 // new space. Thus objects in old space 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, bool data_only) | 105 inline MarkBit(CellType* cell, CellType mask) : cell_(cell), mask_(mask) {} |
106 : cell_(cell), mask_(mask), data_only_(data_only) {} | |
107 | 106 |
108 inline CellType* cell() { return cell_; } | 107 inline CellType* cell() { return cell_; } |
109 inline CellType mask() { return mask_; } | 108 inline CellType mask() { return mask_; } |
110 | 109 |
111 #ifdef DEBUG | 110 #ifdef DEBUG |
112 bool operator==(const MarkBit& other) { | 111 bool operator==(const MarkBit& other) { |
113 return cell_ == other.cell_ && mask_ == other.mask_; | 112 return cell_ == other.cell_ && mask_ == other.mask_; |
114 } | 113 } |
115 #endif | 114 #endif |
116 | 115 |
117 inline void Set() { *cell_ |= mask_; } | 116 inline void Set() { *cell_ |= mask_; } |
118 inline bool Get() { return (*cell_ & mask_) != 0; } | 117 inline bool Get() { return (*cell_ & mask_) != 0; } |
119 inline void Clear() { *cell_ &= ~mask_; } | 118 inline void Clear() { *cell_ &= ~mask_; } |
120 | 119 |
121 inline bool data_only() { return data_only_; } | |
122 | 120 |
123 inline MarkBit Next() { | 121 inline MarkBit Next() { |
124 CellType new_mask = mask_ << 1; | 122 CellType new_mask = mask_ << 1; |
125 if (new_mask == 0) { | 123 if (new_mask == 0) { |
126 return MarkBit(cell_ + 1, 1, data_only_); | 124 return MarkBit(cell_ + 1, 1); |
127 } else { | 125 } else { |
128 return MarkBit(cell_, new_mask, data_only_); | 126 return MarkBit(cell_, new_mask); |
129 } | 127 } |
130 } | 128 } |
131 | 129 |
132 private: | 130 private: |
133 CellType* cell_; | 131 CellType* cell_; |
134 CellType mask_; | 132 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_; | |
140 }; | 133 }; |
141 | 134 |
142 | 135 |
143 // Bitmap is a sequence of cells each containing fixed number of bits. | 136 // Bitmap is a sequence of cells each containing fixed number of bits. |
144 class Bitmap { | 137 class Bitmap { |
145 public: | 138 public: |
146 static const uint32_t kBitsPerCell = 32; | 139 static const uint32_t kBitsPerCell = 32; |
147 static const uint32_t kBitsPerCellLog2 = 5; | 140 static const uint32_t kBitsPerCellLog2 = 5; |
148 static const uint32_t kBitIndexMask = kBitsPerCell - 1; | 141 static const uint32_t kBitIndexMask = kBitsPerCell - 1; |
149 static const uint32_t kBytesPerCell = kBitsPerCell / kBitsPerByte; | 142 static const uint32_t kBytesPerCell = kBitsPerCell / kBitsPerByte; |
(...skipping 30 matching lines...) Expand all Loading... |
180 INLINE(MarkBit::CellType* cells()) { | 173 INLINE(MarkBit::CellType* cells()) { |
181 return reinterpret_cast<MarkBit::CellType*>(this); | 174 return reinterpret_cast<MarkBit::CellType*>(this); |
182 } | 175 } |
183 | 176 |
184 INLINE(Address address()) { return reinterpret_cast<Address>(this); } | 177 INLINE(Address address()) { return reinterpret_cast<Address>(this); } |
185 | 178 |
186 INLINE(static Bitmap* FromAddress(Address addr)) { | 179 INLINE(static Bitmap* FromAddress(Address addr)) { |
187 return reinterpret_cast<Bitmap*>(addr); | 180 return reinterpret_cast<Bitmap*>(addr); |
188 } | 181 } |
189 | 182 |
190 inline MarkBit MarkBitFromIndex(uint32_t index, bool data_only = false) { | 183 inline MarkBit MarkBitFromIndex(uint32_t index) { |
191 MarkBit::CellType mask = 1 << (index & kBitIndexMask); | 184 MarkBit::CellType mask = 1 << (index & kBitIndexMask); |
192 MarkBit::CellType* cell = this->cells() + (index >> kBitsPerCellLog2); | 185 MarkBit::CellType* cell = this->cells() + (index >> kBitsPerCellLog2); |
193 return MarkBit(cell, mask, data_only); | 186 return MarkBit(cell, mask); |
194 } | 187 } |
195 | 188 |
196 static inline void Clear(MemoryChunk* chunk); | 189 static inline void Clear(MemoryChunk* chunk); |
197 | 190 |
198 static void PrintWord(uint32_t word, uint32_t himask = 0) { | 191 static void PrintWord(uint32_t word, uint32_t himask = 0) { |
199 for (uint32_t mask = 1; mask != 0; mask <<= 1) { | 192 for (uint32_t mask = 1; mask != 0; mask <<= 1) { |
200 if ((mask & himask) != 0) PrintF("["); | 193 if ((mask & himask) != 0) PrintF("["); |
201 PrintF((mask & word) ? "1" : "0"); | 194 PrintF((mask & word) ? "1" : "0"); |
202 if ((mask & himask) != 0) PrintF("]"); | 195 if ((mask & himask) != 0) PrintF("]"); |
203 } | 196 } |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 | 356 |
364 enum MemoryChunkFlags { | 357 enum MemoryChunkFlags { |
365 IS_EXECUTABLE, | 358 IS_EXECUTABLE, |
366 ABOUT_TO_BE_FREED, | 359 ABOUT_TO_BE_FREED, |
367 POINTERS_TO_HERE_ARE_INTERESTING, | 360 POINTERS_TO_HERE_ARE_INTERESTING, |
368 POINTERS_FROM_HERE_ARE_INTERESTING, | 361 POINTERS_FROM_HERE_ARE_INTERESTING, |
369 SCAN_ON_SCAVENGE, | 362 SCAN_ON_SCAVENGE, |
370 IN_FROM_SPACE, // Mutually exclusive with IN_TO_SPACE. | 363 IN_FROM_SPACE, // Mutually exclusive with IN_TO_SPACE. |
371 IN_TO_SPACE, // All pages in new space has one of these two set. | 364 IN_TO_SPACE, // All pages in new space has one of these two set. |
372 NEW_SPACE_BELOW_AGE_MARK, | 365 NEW_SPACE_BELOW_AGE_MARK, |
373 CONTAINS_ONLY_DATA, | |
374 EVACUATION_CANDIDATE, | 366 EVACUATION_CANDIDATE, |
375 RESCAN_ON_EVACUATION, | 367 RESCAN_ON_EVACUATION, |
376 NEVER_EVACUATE, // May contain immortal immutables. | 368 NEVER_EVACUATE, // May contain immortal immutables. |
377 | 369 |
378 // WAS_SWEPT indicates that marking bits have been cleared by the sweeper, | 370 // WAS_SWEPT indicates that marking bits have been cleared by the sweeper, |
379 // otherwise marking bits are still intact. | 371 // otherwise marking bits are still intact. |
380 WAS_SWEPT, | 372 WAS_SWEPT, |
381 | 373 |
382 // Large objects can have a progress bar in their page header. These object | 374 // Large objects can have a progress bar in their page header. These object |
383 // are scanned in increments and will be kept black while being scanned. | 375 // 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... |
558 | 550 |
559 void SetArea(Address area_start, Address area_end) { | 551 void SetArea(Address area_start, Address area_end) { |
560 area_start_ = area_start; | 552 area_start_ = area_start; |
561 area_end_ = area_end; | 553 area_end_ = area_end; |
562 } | 554 } |
563 | 555 |
564 Executability executable() { | 556 Executability executable() { |
565 return IsFlagSet(IS_EXECUTABLE) ? EXECUTABLE : NOT_EXECUTABLE; | 557 return IsFlagSet(IS_EXECUTABLE) ? EXECUTABLE : NOT_EXECUTABLE; |
566 } | 558 } |
567 | 559 |
568 bool ContainsOnlyData() { return IsFlagSet(CONTAINS_ONLY_DATA); } | |
569 | |
570 bool InNewSpace() { | 560 bool InNewSpace() { |
571 return (flags_ & ((1 << IN_FROM_SPACE) | (1 << IN_TO_SPACE))) != 0; | 561 return (flags_ & ((1 << IN_FROM_SPACE) | (1 << IN_TO_SPACE))) != 0; |
572 } | 562 } |
573 | 563 |
574 bool InToSpace() { return IsFlagSet(IN_TO_SPACE); } | 564 bool InToSpace() { return IsFlagSet(IN_TO_SPACE); } |
575 | 565 |
576 bool InFromSpace() { return IsFlagSet(IN_FROM_SPACE); } | 566 bool InFromSpace() { return IsFlagSet(IN_FROM_SPACE); } |
577 | 567 |
578 // --------------------------------------------------------------------- | 568 // --------------------------------------------------------------------- |
579 // Markbits support | 569 // Markbits support |
(...skipping 2009 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2589 MUST_USE_RESULT AllocationResult SlowAllocateRaw(int size_in_bytes); | 2579 MUST_USE_RESULT AllocationResult SlowAllocateRaw(int size_in_bytes); |
2590 | 2580 |
2591 friend class SemiSpaceIterator; | 2581 friend class SemiSpaceIterator; |
2592 | 2582 |
2593 public: | 2583 public: |
2594 TRACK_MEMORY("NewSpace") | 2584 TRACK_MEMORY("NewSpace") |
2595 }; | 2585 }; |
2596 | 2586 |
2597 | 2587 |
2598 // ----------------------------------------------------------------------------- | 2588 // ----------------------------------------------------------------------------- |
2599 // Old object space (excluding map objects) | 2589 // Old object space (includes the old space of objects and code space) |
2600 | 2590 |
2601 class OldSpace : public PagedSpace { | 2591 class OldSpace : public PagedSpace { |
2602 public: | 2592 public: |
2603 // Creates an old space object with a given maximum capacity. | 2593 // Creates an old space object with a given maximum capacity. |
2604 // The constructor does not allocate pages from OS. | 2594 // The constructor does not allocate pages from OS. |
2605 OldSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id, | 2595 OldSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id, |
2606 Executability executable) | 2596 Executability executable) |
2607 : PagedSpace(heap, max_capacity, id, executable) {} | 2597 : PagedSpace(heap, max_capacity, id, executable) {} |
2608 | 2598 |
2609 public: | 2599 public: |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2823 | 2813 |
2824 // Iterates over the chunks (pages and large object pages) that can contain | 2814 // Iterates over the chunks (pages and large object pages) that can contain |
2825 // pointers to new space. | 2815 // pointers to new space. |
2826 class PointerChunkIterator BASE_EMBEDDED { | 2816 class PointerChunkIterator BASE_EMBEDDED { |
2827 public: | 2817 public: |
2828 inline explicit PointerChunkIterator(Heap* heap); | 2818 inline explicit PointerChunkIterator(Heap* heap); |
2829 | 2819 |
2830 // Return NULL when the iterator is done. | 2820 // Return NULL when the iterator is done. |
2831 MemoryChunk* next() { | 2821 MemoryChunk* next() { |
2832 switch (state_) { | 2822 switch (state_) { |
2833 case kOldPointerState: { | 2823 case kOldSpaceState: { |
2834 if (old_pointer_iterator_.has_next()) { | 2824 if (old_pointer_iterator_.has_next()) { |
2835 return old_pointer_iterator_.next(); | 2825 return old_pointer_iterator_.next(); |
2836 } | 2826 } |
2837 state_ = kMapState; | 2827 state_ = kMapState; |
2838 // Fall through. | 2828 // Fall through. |
2839 } | 2829 } |
2840 case kMapState: { | 2830 case kMapState: { |
2841 if (map_iterator_.has_next()) { | 2831 if (map_iterator_.has_next()) { |
2842 return map_iterator_.next(); | 2832 return map_iterator_.next(); |
2843 } | 2833 } |
(...skipping 18 matching lines...) Expand all Loading... |
2862 return NULL; | 2852 return NULL; |
2863 default: | 2853 default: |
2864 break; | 2854 break; |
2865 } | 2855 } |
2866 UNREACHABLE(); | 2856 UNREACHABLE(); |
2867 return NULL; | 2857 return NULL; |
2868 } | 2858 } |
2869 | 2859 |
2870 | 2860 |
2871 private: | 2861 private: |
2872 enum State { kOldPointerState, kMapState, kLargeObjectState, kFinishedState }; | 2862 enum State { kOldSpaceState, kMapState, kLargeObjectState, kFinishedState }; |
2873 State state_; | 2863 State state_; |
2874 PageIterator old_pointer_iterator_; | 2864 PageIterator old_pointer_iterator_; |
2875 PageIterator map_iterator_; | 2865 PageIterator map_iterator_; |
2876 LargeObjectIterator lo_iterator_; | 2866 LargeObjectIterator lo_iterator_; |
2877 }; | 2867 }; |
2878 | 2868 |
2879 | 2869 |
2880 #ifdef DEBUG | 2870 #ifdef DEBUG |
2881 struct CommentStatistic { | 2871 struct CommentStatistic { |
2882 const char* comment; | 2872 const char* comment; |
2883 int size; | 2873 int size; |
2884 int count; | 2874 int count; |
2885 void Clear() { | 2875 void Clear() { |
2886 comment = NULL; | 2876 comment = NULL; |
2887 size = 0; | 2877 size = 0; |
2888 count = 0; | 2878 count = 0; |
2889 } | 2879 } |
2890 // Must be small, since an iteration is used for lookup. | 2880 // Must be small, since an iteration is used for lookup. |
2891 static const int kMaxComments = 64; | 2881 static const int kMaxComments = 64; |
2892 }; | 2882 }; |
2893 #endif | 2883 #endif |
2894 } | 2884 } |
2895 } // namespace v8::internal | 2885 } // namespace v8::internal |
2896 | 2886 |
2897 #endif // V8_HEAP_SPACES_H_ | 2887 #endif // V8_HEAP_SPACES_H_ |
OLD | NEW |