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/atomic-utils.h" | 9 #include "src/atomic-utils.h" |
10 #include "src/base/atomicops.h" | 10 #include "src/base/atomicops.h" |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 | 261 |
262 class SkipList; | 262 class SkipList; |
263 class SlotsBuffer; | 263 class SlotsBuffer; |
264 | 264 |
265 // MemoryChunk represents a memory region owned by a specific space. | 265 // MemoryChunk represents a memory region owned by a specific space. |
266 // It is divided into the header and the body. Chunk start is always | 266 // It is divided into the header and the body. Chunk start is always |
267 // 1MB aligned. Start of the body is aligned so it can accommodate | 267 // 1MB aligned. Start of the body is aligned so it can accommodate |
268 // any heap object. | 268 // any heap object. |
269 class MemoryChunk { | 269 class MemoryChunk { |
270 public: | 270 public: |
| 271 // |kCompactionDone|: Initial compaction state of a |MemoryChunk|. |
| 272 // |kCompactingFinalize|: Parallel compaction is done but the chunk needs to |
| 273 // be finalized. |
| 274 // |kCompactingInProgress|: Parallel compaction is currently in progress. |
| 275 // |kCompactingAborted|: Parallel compaction has been aborted, which should |
| 276 // for now only happen in OOM scenarios. |
| 277 // |kNoEvacuationCandidate|: Page was no evacuation candidate by the time the |
| 278 // compactor inspected it. |
| 279 enum ParallelCompactingState { |
| 280 kCompactingDone, |
| 281 kCompactingFinalize, |
| 282 kCompactingInProgress, |
| 283 kCompactingAborted, |
| 284 kNoEvacuationCandidate, |
| 285 }; |
| 286 |
271 // Only works if the pointer is in the first kPageSize of the MemoryChunk. | 287 // Only works if the pointer is in the first kPageSize of the MemoryChunk. |
272 static MemoryChunk* FromAddress(Address a) { | 288 static MemoryChunk* FromAddress(Address a) { |
273 return reinterpret_cast<MemoryChunk*>(OffsetFrom(a) & ~kAlignmentMask); | 289 return reinterpret_cast<MemoryChunk*>(OffsetFrom(a) & ~kAlignmentMask); |
274 } | 290 } |
275 static const MemoryChunk* FromAddress(const byte* a) { | 291 static const MemoryChunk* FromAddress(const byte* a) { |
276 return reinterpret_cast<const MemoryChunk*>(OffsetFrom(a) & | 292 return reinterpret_cast<const MemoryChunk*>(OffsetFrom(a) & |
277 ~kAlignmentMask); | 293 ~kAlignmentMask); |
278 } | 294 } |
279 | 295 |
280 // Only works for addresses in pointer spaces, not data or code spaces. | 296 // Only works for addresses in pointer spaces, not data or code spaces. |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
451 | 467 |
452 ParallelSweepingState parallel_sweeping() { | 468 ParallelSweepingState parallel_sweeping() { |
453 return static_cast<ParallelSweepingState>( | 469 return static_cast<ParallelSweepingState>( |
454 base::Acquire_Load(¶llel_sweeping_)); | 470 base::Acquire_Load(¶llel_sweeping_)); |
455 } | 471 } |
456 | 472 |
457 void set_parallel_sweeping(ParallelSweepingState state) { | 473 void set_parallel_sweeping(ParallelSweepingState state) { |
458 base::Release_Store(¶llel_sweeping_, state); | 474 base::Release_Store(¶llel_sweeping_, state); |
459 } | 475 } |
460 | 476 |
| 477 AtomicValue<ParallelCompactingState>& parallel_compaction_state() { |
| 478 return parallel_compaction_; |
| 479 } |
| 480 |
461 bool TryLock() { return mutex_->TryLock(); } | 481 bool TryLock() { return mutex_->TryLock(); } |
462 | 482 |
463 base::Mutex* mutex() { return mutex_; } | 483 base::Mutex* mutex() { return mutex_; } |
464 | 484 |
465 // WaitUntilSweepingCompleted only works when concurrent sweeping is in | 485 // WaitUntilSweepingCompleted only works when concurrent sweeping is in |
466 // progress. In particular, when we know that right before this call a | 486 // progress. In particular, when we know that right before this call a |
467 // sweeper thread was sweeping this page. | 487 // sweeper thread was sweeping this page. |
468 void WaitUntilSweepingCompleted() { | 488 void WaitUntilSweepingCompleted() { |
469 mutex_->Lock(); | 489 mutex_->Lock(); |
470 mutex_->Unlock(); | 490 mutex_->Unlock(); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
559 kSlotsBufferOffset + kPointerSize // SlotsBuffer* slots_buffer_; | 579 kSlotsBufferOffset + kPointerSize // SlotsBuffer* slots_buffer_; |
560 + kPointerSize; // SkipList* skip_list_; | 580 + kPointerSize; // SkipList* skip_list_; |
561 | 581 |
562 static const size_t kMinHeaderSize = | 582 static const size_t kMinHeaderSize = |
563 kWriteBarrierCounterOffset + | 583 kWriteBarrierCounterOffset + |
564 kIntptrSize // intptr_t write_barrier_counter_ | 584 kIntptrSize // intptr_t write_barrier_counter_ |
565 + kIntSize // int progress_bar_ | 585 + kIntSize // int progress_bar_ |
566 + kPointerSize // AtomicValue high_water_mark_ | 586 + kPointerSize // AtomicValue high_water_mark_ |
567 + kPointerSize // base::Mutex* mutex_ | 587 + kPointerSize // base::Mutex* mutex_ |
568 + kPointerSize // base::AtomicWord parallel_sweeping_ | 588 + kPointerSize // base::AtomicWord parallel_sweeping_ |
| 589 + kPointerSize // AtomicFlag parallel_compaction_ |
569 + 5 * kPointerSize // AtomicNumber free-list statistics | 590 + 5 * kPointerSize // AtomicNumber free-list statistics |
570 + kPointerSize // base::AtomicWord next_chunk_ | 591 + kPointerSize // base::AtomicWord next_chunk_ |
571 + kPointerSize; // base::AtomicWord prev_chunk_ | 592 + kPointerSize; // base::AtomicWord prev_chunk_ |
572 | 593 |
573 // We add some more space to the computed header size to amount for missing | 594 // We add some more space to the computed header size to amount for missing |
574 // alignment requirements in our computation. | 595 // alignment requirements in our computation. |
575 // Try to get kHeaderSize properly aligned on 32-bit and 64-bit machines. | 596 // Try to get kHeaderSize properly aligned on 32-bit and 64-bit machines. |
576 static const size_t kHeaderSize = kMinHeaderSize + kIntSize; | 597 static const size_t kHeaderSize = kMinHeaderSize + kIntSize; |
577 | 598 |
578 static const int kBodyOffset = | 599 static const int kBodyOffset = |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
687 // to another chunk. See the comment to Page::FromAllocationTop. | 708 // to another chunk. See the comment to Page::FromAllocationTop. |
688 MemoryChunk* chunk = MemoryChunk::FromAddress(mark - 1); | 709 MemoryChunk* chunk = MemoryChunk::FromAddress(mark - 1); |
689 intptr_t new_mark = static_cast<intptr_t>(mark - chunk->address()); | 710 intptr_t new_mark = static_cast<intptr_t>(mark - chunk->address()); |
690 intptr_t old_mark = 0; | 711 intptr_t old_mark = 0; |
691 do { | 712 do { |
692 old_mark = chunk->high_water_mark_.Value(); | 713 old_mark = chunk->high_water_mark_.Value(); |
693 } while ((new_mark > old_mark) && | 714 } while ((new_mark > old_mark) && |
694 !chunk->high_water_mark_.TrySetValue(old_mark, new_mark)); | 715 !chunk->high_water_mark_.TrySetValue(old_mark, new_mark)); |
695 } | 716 } |
696 | 717 |
| 718 |
| 719 #define FRAGMENTATION_STATS_ACCESSORS(type, name) \ |
| 720 type name() { return name##_.Value(); } \ |
| 721 void set_##name(type name) { name##_.SetValue(name); } \ |
| 722 void add_##name(type name) { name##_.Increment(name); } |
| 723 |
| 724 FRAGMENTATION_STATS_ACCESSORS(intptr_t, non_available_small_blocks) |
| 725 FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_small_free_list) |
| 726 FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_medium_free_list) |
| 727 FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_large_free_list) |
| 728 FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_huge_free_list) |
| 729 |
| 730 #undef FRAGMENTATION_STATS_ACCESSORS |
| 731 |
697 protected: | 732 protected: |
698 size_t size_; | 733 size_t size_; |
699 intptr_t flags_; | 734 intptr_t flags_; |
700 | 735 |
701 // Start and end of allocatable memory on this chunk. | 736 // Start and end of allocatable memory on this chunk. |
702 Address area_start_; | 737 Address area_start_; |
703 Address area_end_; | 738 Address area_end_; |
704 | 739 |
705 // If the chunk needs to remember its memory reservation, it is stored here. | 740 // If the chunk needs to remember its memory reservation, it is stored here. |
706 base::VirtualMemory reservation_; | 741 base::VirtualMemory reservation_; |
(...skipping 12 matching lines...) Expand all Loading... |
719 intptr_t write_barrier_counter_; | 754 intptr_t write_barrier_counter_; |
720 // Used by the incremental marker to keep track of the scanning progress in | 755 // Used by the incremental marker to keep track of the scanning progress in |
721 // large objects that have a progress bar and are scanned in increments. | 756 // large objects that have a progress bar and are scanned in increments. |
722 int progress_bar_; | 757 int progress_bar_; |
723 // Assuming the initial allocation on a page is sequential, | 758 // Assuming the initial allocation on a page is sequential, |
724 // count highest number of bytes ever allocated on the page. | 759 // count highest number of bytes ever allocated on the page. |
725 AtomicValue<intptr_t> high_water_mark_; | 760 AtomicValue<intptr_t> high_water_mark_; |
726 | 761 |
727 base::Mutex* mutex_; | 762 base::Mutex* mutex_; |
728 base::AtomicWord parallel_sweeping_; | 763 base::AtomicWord parallel_sweeping_; |
| 764 AtomicValue<ParallelCompactingState> parallel_compaction_; |
729 | 765 |
730 // PagedSpace free-list statistics. | 766 // PagedSpace free-list statistics. |
731 AtomicNumber<intptr_t> available_in_small_free_list_; | 767 AtomicNumber<intptr_t> available_in_small_free_list_; |
732 AtomicNumber<intptr_t> available_in_medium_free_list_; | 768 AtomicNumber<intptr_t> available_in_medium_free_list_; |
733 AtomicNumber<intptr_t> available_in_large_free_list_; | 769 AtomicNumber<intptr_t> available_in_large_free_list_; |
734 AtomicNumber<intptr_t> available_in_huge_free_list_; | 770 AtomicNumber<intptr_t> available_in_huge_free_list_; |
735 AtomicNumber<intptr_t> non_available_small_blocks_; | 771 AtomicNumber<intptr_t> non_available_small_blocks_; |
736 | 772 |
737 // next_chunk_ holds a pointer of type MemoryChunk | 773 // next_chunk_ holds a pointer of type MemoryChunk |
738 base::AtomicWord next_chunk_; | 774 base::AtomicWord next_chunk_; |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1014 } | 1050 } |
1015 | 1051 |
1016 Address start; | 1052 Address start; |
1017 size_t size; | 1053 size_t size; |
1018 }; | 1054 }; |
1019 | 1055 |
1020 // The global mutex guards free_list_ and allocation_list_ as GC threads may | 1056 // The global mutex guards free_list_ and allocation_list_ as GC threads may |
1021 // access both lists concurrently to the main thread. | 1057 // access both lists concurrently to the main thread. |
1022 base::Mutex code_range_mutex_; | 1058 base::Mutex code_range_mutex_; |
1023 | 1059 |
| 1060 // ReserveBlock can be calleed concurrently. TODO: Merge this into a single |
| 1061 // lock for CodeRange. |
| 1062 base::Mutex reserve_block_mutex_; |
| 1063 |
1024 // Freed blocks of memory are added to the free list. When the allocation | 1064 // Freed blocks of memory are added to the free list. When the allocation |
1025 // list is exhausted, the free list is sorted and merged to make the new | 1065 // list is exhausted, the free list is sorted and merged to make the new |
1026 // allocation list. | 1066 // allocation list. |
1027 List<FreeBlock> free_list_; | 1067 List<FreeBlock> free_list_; |
1028 | 1068 |
1029 // Memory is allocated from the free blocks on the allocation list. | 1069 // Memory is allocated from the free blocks on the allocation list. |
1030 // The block at current_allocation_block_index_ is the current block. | 1070 // The block at current_allocation_block_index_ is the current block. |
1031 List<FreeBlock> allocation_list_; | 1071 List<FreeBlock> allocation_list_; |
1032 int current_allocation_block_index_; | 1072 int current_allocation_block_index_; |
1033 | 1073 |
(...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1606 // and limit when the object we need to allocate is 256-2047 words in size. | 1646 // and limit when the object we need to allocate is 256-2047 words in size. |
1607 // These spaces are call large. | 1647 // These spaces are call large. |
1608 // At least 16384 words. This list is for objects of 2048 words or larger. | 1648 // At least 16384 words. This list is for objects of 2048 words or larger. |
1609 // Empty pages are added to this list. These spaces are called huge. | 1649 // Empty pages are added to this list. These spaces are called huge. |
1610 class FreeList { | 1650 class FreeList { |
1611 public: | 1651 public: |
1612 explicit FreeList(PagedSpace* owner); | 1652 explicit FreeList(PagedSpace* owner); |
1613 | 1653 |
1614 intptr_t Concatenate(FreeList* free_list); | 1654 intptr_t Concatenate(FreeList* free_list); |
1615 | 1655 |
| 1656 // Evenly divide available blocks into {free_lists_to_fill}. |
| 1657 void Divide(FreeList** free_lists_to_fill, size_t num); |
| 1658 |
1616 // Clear the free list. | 1659 // Clear the free list. |
1617 void Reset(); | 1660 void Reset(); |
1618 | 1661 |
1619 // Return the number of bytes available on the free list. | 1662 // Return the number of bytes available on the free list. |
1620 intptr_t available() { | 1663 intptr_t available() { |
1621 return small_list_.available() + medium_list_.available() + | 1664 return small_list_.available() + medium_list_.available() + |
1622 large_list_.available() + huge_list_.available(); | 1665 large_list_.available() + huge_list_.available(); |
1623 } | 1666 } |
1624 | 1667 |
1625 // Place a node on the free list. The block of size 'size_in_bytes' | 1668 // Place a node on the free list. The block of size 'size_in_bytes' |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1666 void RepairLists(Heap* heap); | 1709 void RepairLists(Heap* heap); |
1667 | 1710 |
1668 intptr_t EvictFreeListItems(Page* p); | 1711 intptr_t EvictFreeListItems(Page* p); |
1669 bool ContainsPageFreeListItems(Page* p); | 1712 bool ContainsPageFreeListItems(Page* p); |
1670 | 1713 |
1671 FreeListCategory* small_list() { return &small_list_; } | 1714 FreeListCategory* small_list() { return &small_list_; } |
1672 FreeListCategory* medium_list() { return &medium_list_; } | 1715 FreeListCategory* medium_list() { return &medium_list_; } |
1673 FreeListCategory* large_list() { return &large_list_; } | 1716 FreeListCategory* large_list() { return &large_list_; } |
1674 FreeListCategory* huge_list() { return &huge_list_; } | 1717 FreeListCategory* huge_list() { return &huge_list_; } |
1675 | 1718 |
| 1719 |
1676 private: | 1720 private: |
1677 // The size range of blocks, in bytes. | 1721 // The size range of blocks, in bytes. |
1678 static const int kMinBlockSize = 3 * kPointerSize; | 1722 static const int kMinBlockSize = 3 * kPointerSize; |
1679 static const int kMaxBlockSize = Page::kMaxRegularHeapObjectSize; | 1723 static const int kMaxBlockSize = Page::kMaxRegularHeapObjectSize; |
1680 | 1724 |
1681 static const int kSmallListMin = 0x1f * kPointerSize; | 1725 static const int kSmallListMin = 0x1f * kPointerSize; |
1682 static const int kSmallListMax = 0xff * kPointerSize; | 1726 static const int kSmallListMax = 0xff * kPointerSize; |
1683 static const int kMediumListMax = 0x7ff * kPointerSize; | 1727 static const int kMediumListMax = 0x7ff * kPointerSize; |
1684 static const int kLargeListMax = 0x3fff * kPointerSize; | 1728 static const int kLargeListMax = 0x3fff * kPointerSize; |
1685 static const int kSmallAllocationMax = kSmallListMin; | 1729 static const int kSmallAllocationMax = kSmallListMin; |
1686 static const int kMediumAllocationMax = kSmallListMax; | 1730 static const int kMediumAllocationMax = kSmallListMax; |
1687 static const int kLargeAllocationMax = kMediumListMax; | 1731 static const int kLargeAllocationMax = kMediumListMax; |
1688 | 1732 |
1689 FreeSpace* FindNodeFor(int size_in_bytes, int* node_size); | 1733 FreeSpace* FindNodeFor(int size_in_bytes, int* node_size); |
1690 | 1734 |
1691 PagedSpace* owner_; | 1735 PagedSpace* owner_; |
1692 Heap* heap_; | 1736 Heap* heap_; |
1693 FreeListCategory small_list_; | 1737 FreeListCategory small_list_; |
1694 FreeListCategory medium_list_; | 1738 FreeListCategory medium_list_; |
1695 FreeListCategory large_list_; | 1739 FreeListCategory large_list_; |
1696 FreeListCategory huge_list_; | 1740 FreeListCategory huge_list_; |
1697 | 1741 |
| 1742 friend class CompactionSpace; |
| 1743 |
1698 DISALLOW_IMPLICIT_CONSTRUCTORS(FreeList); | 1744 DISALLOW_IMPLICIT_CONSTRUCTORS(FreeList); |
1699 }; | 1745 }; |
1700 | 1746 |
1701 | 1747 |
1702 class AllocationResult { | 1748 class AllocationResult { |
1703 public: | 1749 public: |
1704 // Implicit constructor from Object*. | 1750 // Implicit constructor from Object*. |
1705 AllocationResult(Object* object) // NOLINT | 1751 AllocationResult(Object* object) // NOLINT |
1706 : object_(object) { | 1752 : object_(object) { |
1707 // AllocationResults can't return Smis, which are used to represent | 1753 // AllocationResults can't return Smis, which are used to represent |
(...skipping 1029 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2737 IncreaseCapacity(size_in_bytes); | 2783 IncreaseCapacity(size_in_bytes); |
2738 Free(start, size_in_bytes); | 2784 Free(start, size_in_bytes); |
2739 } | 2785 } |
2740 | 2786 |
2741 protected: | 2787 protected: |
2742 // The space is temporary and not included in any snapshots. | 2788 // The space is temporary and not included in any snapshots. |
2743 virtual bool snapshotable() { return false; } | 2789 virtual bool snapshotable() { return false; } |
2744 }; | 2790 }; |
2745 | 2791 |
2746 | 2792 |
| 2793 class CompactionSpaces : public Malloced { |
| 2794 public: |
| 2795 explicit CompactionSpaces(Heap* heap) |
| 2796 : old_space_(new CompactionSpace(heap, OLD_SPACE, |
| 2797 Executability::NOT_EXECUTABLE)), |
| 2798 code_space_( |
| 2799 new CompactionSpace(heap, CODE_SPACE, Executability::EXECUTABLE)) {} |
| 2800 |
| 2801 ~CompactionSpaces() { |
| 2802 delete old_space_; |
| 2803 delete code_space_; |
| 2804 } |
| 2805 |
| 2806 CompactionSpace* Get(AllocationSpace space) { |
| 2807 switch (space) { |
| 2808 case OLD_SPACE: |
| 2809 DCHECK(old_space_ != nullptr); |
| 2810 return old_space_; |
| 2811 case CODE_SPACE: |
| 2812 DCHECK(code_space_ != nullptr); |
| 2813 return code_space_; |
| 2814 default: |
| 2815 UNREACHABLE(); |
| 2816 } |
| 2817 UNREACHABLE(); |
| 2818 return nullptr; |
| 2819 } |
| 2820 |
| 2821 private: |
| 2822 CompactionSpace* old_space_; |
| 2823 CompactionSpace* code_space_; |
| 2824 }; |
| 2825 |
| 2826 |
2747 // ----------------------------------------------------------------------------- | 2827 // ----------------------------------------------------------------------------- |
2748 // Old object space (includes the old space of objects and code space) | 2828 // Old object space (includes the old space of objects and code space) |
2749 | 2829 |
2750 class OldSpace : public PagedSpace { | 2830 class OldSpace : public PagedSpace { |
2751 public: | 2831 public: |
2752 // Creates an old space object. The constructor does not allocate pages | 2832 // Creates an old space object. The constructor does not allocate pages |
2753 // from OS. | 2833 // from OS. |
2754 OldSpace(Heap* heap, AllocationSpace id, Executability executable) | 2834 OldSpace(Heap* heap, AllocationSpace id, Executability executable) |
2755 : PagedSpace(heap, id, executable) {} | 2835 : PagedSpace(heap, id, executable) {} |
2756 }; | 2836 }; |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2937 count = 0; | 3017 count = 0; |
2938 } | 3018 } |
2939 // Must be small, since an iteration is used for lookup. | 3019 // Must be small, since an iteration is used for lookup. |
2940 static const int kMaxComments = 64; | 3020 static const int kMaxComments = 64; |
2941 }; | 3021 }; |
2942 #endif | 3022 #endif |
2943 } | 3023 } |
2944 } // namespace v8::internal | 3024 } // namespace v8::internal |
2945 | 3025 |
2946 #endif // V8_HEAP_SPACES_H_ | 3026 #endif // V8_HEAP_SPACES_H_ |
OLD | NEW |