OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 #include "src/heap/mark-compact.h" | 5 #include "src/heap/mark-compact.h" |
6 | 6 |
7 #include "src/base/atomicops.h" | 7 #include "src/base/atomicops.h" |
8 #include "src/base/bits.h" | 8 #include "src/base/bits.h" |
9 #include "src/base/sys-info.h" | 9 #include "src/base/sys-info.h" |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
(...skipping 1816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1827 return allocation; | 1827 return allocation; |
1828 } | 1828 } |
1829 | 1829 |
1830 LocalAllocationBuffer buffer_; | 1830 LocalAllocationBuffer buffer_; |
1831 AllocationSpace space_to_allocate_; | 1831 AllocationSpace space_to_allocate_; |
1832 intptr_t promoted_size_; | 1832 intptr_t promoted_size_; |
1833 intptr_t semispace_copied_size_; | 1833 intptr_t semispace_copied_size_; |
1834 base::HashMap* local_pretenuring_feedback_; | 1834 base::HashMap* local_pretenuring_feedback_; |
1835 }; | 1835 }; |
1836 | 1836 |
| 1837 template <PageEvacuationMode mode> |
1837 class MarkCompactCollector::EvacuateNewSpacePageVisitor final | 1838 class MarkCompactCollector::EvacuateNewSpacePageVisitor final |
1838 : public MarkCompactCollector::HeapObjectVisitor { | 1839 : public MarkCompactCollector::HeapObjectVisitor { |
1839 public: | 1840 public: |
1840 explicit EvacuateNewSpacePageVisitor(Heap* heap) | 1841 explicit EvacuateNewSpacePageVisitor( |
1841 : heap_(heap), promoted_size_(0), semispace_copied_size_(0) {} | 1842 Heap* heap, base::HashMap* local_pretenuring_feedback) |
| 1843 : heap_(heap), |
| 1844 moved_bytes_(0), |
| 1845 local_pretenuring_feedback_(local_pretenuring_feedback) {} |
1842 | 1846 |
1843 static void MoveToOldSpace(Page* page, PagedSpace* owner) { | 1847 static void Move(Page* page) { |
1844 page->Unlink(); | 1848 switch (mode) { |
1845 Page* new_page = Page::ConvertNewToOld(page, owner); | 1849 case NEW_TO_NEW: |
1846 new_page->SetFlag(Page::PAGE_NEW_OLD_PROMOTION); | 1850 page->heap()->new_space()->MovePageFromSpaceToSpace(page); |
1847 } | 1851 page->SetFlag(Page::PAGE_NEW_NEW_PROMOTION); |
1848 | 1852 break; |
1849 static void MoveToToSpace(Page* page) { | 1853 case NEW_TO_OLD: { |
1850 page->heap()->new_space()->MovePageFromSpaceToSpace(page); | 1854 page->Unlink(); |
1851 page->SetFlag(Page::PAGE_NEW_NEW_PROMOTION); | 1855 Page* new_page = Page::ConvertNewToOld(page); |
| 1856 new_page->SetFlag(Page::PAGE_NEW_OLD_PROMOTION); |
| 1857 break; |
| 1858 } |
| 1859 } |
1852 } | 1860 } |
1853 | 1861 |
1854 inline bool Visit(HeapObject* object) { | 1862 inline bool Visit(HeapObject* object) { |
1855 RecordMigratedSlotVisitor visitor(heap_->mark_compact_collector()); | 1863 heap_->UpdateAllocationSite<Heap::kCached>(object, |
1856 object->IterateBodyFast(&visitor); | 1864 local_pretenuring_feedback_); |
1857 promoted_size_ += object->Size(); | 1865 if (mode == NEW_TO_OLD) { |
| 1866 RecordMigratedSlotVisitor visitor(heap_->mark_compact_collector()); |
| 1867 object->IterateBodyFast(&visitor); |
| 1868 } |
1858 return true; | 1869 return true; |
1859 } | 1870 } |
1860 | 1871 |
1861 intptr_t promoted_size() { return promoted_size_; } | 1872 intptr_t moved_bytes() { return moved_bytes_; } |
1862 intptr_t semispace_copied_size() { return semispace_copied_size_; } | 1873 void account_moved_bytes(intptr_t bytes) { moved_bytes_ += bytes; } |
1863 | |
1864 void account_semispace_copied(intptr_t copied) { | |
1865 semispace_copied_size_ += copied; | |
1866 } | |
1867 | 1874 |
1868 private: | 1875 private: |
1869 Heap* heap_; | 1876 Heap* heap_; |
1870 intptr_t promoted_size_; | 1877 intptr_t moved_bytes_; |
1871 intptr_t semispace_copied_size_; | 1878 base::HashMap* local_pretenuring_feedback_; |
1872 }; | 1879 }; |
1873 | 1880 |
1874 class MarkCompactCollector::EvacuateOldSpaceVisitor final | 1881 class MarkCompactCollector::EvacuateOldSpaceVisitor final |
1875 : public MarkCompactCollector::EvacuateVisitorBase { | 1882 : public MarkCompactCollector::EvacuateVisitorBase { |
1876 public: | 1883 public: |
1877 EvacuateOldSpaceVisitor(Heap* heap, | 1884 EvacuateOldSpaceVisitor(Heap* heap, |
1878 CompactionSpaceCollection* compaction_spaces) | 1885 CompactionSpaceCollection* compaction_spaces) |
1879 : EvacuateVisitorBase(heap, compaction_spaces) {} | 1886 : EvacuateVisitorBase(heap, compaction_spaces) {} |
1880 | 1887 |
1881 inline bool Visit(HeapObject* object) override { | 1888 inline bool Visit(HeapObject* object) override { |
(...skipping 1036 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2918 return FLAG_page_promotion_threshold * Page::kAllocatableMemory / 100; | 2925 return FLAG_page_promotion_threshold * Page::kAllocatableMemory / 100; |
2919 return Page::kAllocatableMemory + kPointerSize; | 2926 return Page::kAllocatableMemory + kPointerSize; |
2920 } | 2927 } |
2921 | 2928 |
2922 explicit Evacuator(MarkCompactCollector* collector) | 2929 explicit Evacuator(MarkCompactCollector* collector) |
2923 : collector_(collector), | 2930 : collector_(collector), |
2924 compaction_spaces_(collector->heap()), | 2931 compaction_spaces_(collector->heap()), |
2925 local_pretenuring_feedback_(kInitialLocalPretenuringFeedbackCapacity), | 2932 local_pretenuring_feedback_(kInitialLocalPretenuringFeedbackCapacity), |
2926 new_space_visitor_(collector->heap(), &compaction_spaces_, | 2933 new_space_visitor_(collector->heap(), &compaction_spaces_, |
2927 &local_pretenuring_feedback_), | 2934 &local_pretenuring_feedback_), |
2928 new_space_page_visitor(collector->heap()), | 2935 new_to_new_page_visitor_(collector->heap(), |
| 2936 &local_pretenuring_feedback_), |
| 2937 new_to_old_page_visitor_(collector->heap(), |
| 2938 &local_pretenuring_feedback_), |
| 2939 |
2929 old_space_visitor_(collector->heap(), &compaction_spaces_), | 2940 old_space_visitor_(collector->heap(), &compaction_spaces_), |
2930 duration_(0.0), | 2941 duration_(0.0), |
2931 bytes_compacted_(0) {} | 2942 bytes_compacted_(0) {} |
2932 | 2943 |
2933 inline bool EvacuatePage(Page* chunk); | 2944 inline bool EvacuatePage(Page* chunk); |
2934 | 2945 |
2935 // Merge back locally cached info sequentially. Note that this method needs | 2946 // Merge back locally cached info sequentially. Note that this method needs |
2936 // to be called from the main thread. | 2947 // to be called from the main thread. |
2937 inline void Finalize(); | 2948 inline void Finalize(); |
2938 | 2949 |
(...skipping 10 matching lines...) Expand all Loading... |
2949 } | 2960 } |
2950 | 2961 |
2951 MarkCompactCollector* collector_; | 2962 MarkCompactCollector* collector_; |
2952 | 2963 |
2953 // Locally cached collector data. | 2964 // Locally cached collector data. |
2954 CompactionSpaceCollection compaction_spaces_; | 2965 CompactionSpaceCollection compaction_spaces_; |
2955 base::HashMap local_pretenuring_feedback_; | 2966 base::HashMap local_pretenuring_feedback_; |
2956 | 2967 |
2957 // Visitors for the corresponding spaces. | 2968 // Visitors for the corresponding spaces. |
2958 EvacuateNewSpaceVisitor new_space_visitor_; | 2969 EvacuateNewSpaceVisitor new_space_visitor_; |
2959 EvacuateNewSpacePageVisitor new_space_page_visitor; | 2970 EvacuateNewSpacePageVisitor<PageEvacuationMode::NEW_TO_NEW> |
| 2971 new_to_new_page_visitor_; |
| 2972 EvacuateNewSpacePageVisitor<PageEvacuationMode::NEW_TO_OLD> |
| 2973 new_to_old_page_visitor_; |
2960 EvacuateOldSpaceVisitor old_space_visitor_; | 2974 EvacuateOldSpaceVisitor old_space_visitor_; |
2961 | 2975 |
2962 // Book keeping info. | 2976 // Book keeping info. |
2963 double duration_; | 2977 double duration_; |
2964 intptr_t bytes_compacted_; | 2978 intptr_t bytes_compacted_; |
2965 }; | 2979 }; |
2966 | 2980 |
2967 bool MarkCompactCollector::Evacuator::EvacuatePage(Page* page) { | 2981 bool MarkCompactCollector::Evacuator::EvacuatePage(Page* page) { |
2968 bool success = false; | 2982 bool success = false; |
2969 DCHECK(page->SweepingDone()); | 2983 DCHECK(page->SweepingDone()); |
2970 int saved_live_bytes = page->LiveBytes(); | 2984 int saved_live_bytes = page->LiveBytes(); |
2971 double evacuation_time = 0.0; | 2985 double evacuation_time = 0.0; |
2972 Heap* heap = page->heap(); | 2986 Heap* heap = page->heap(); |
2973 { | 2987 { |
2974 AlwaysAllocateScope always_allocate(heap->isolate()); | 2988 AlwaysAllocateScope always_allocate(heap->isolate()); |
2975 TimedScope timed_scope(&evacuation_time); | 2989 TimedScope timed_scope(&evacuation_time); |
2976 switch (ComputeEvacuationMode(page)) { | 2990 switch (ComputeEvacuationMode(page)) { |
2977 case kObjectsNewToOld: | 2991 case kObjectsNewToOld: |
2978 success = collector_->VisitLiveObjects(page, &new_space_visitor_, | 2992 success = collector_->VisitLiveObjects(page, &new_space_visitor_, |
2979 kClearMarkbits); | 2993 kClearMarkbits); |
| 2994 DCHECK(success); |
2980 ArrayBufferTracker::ProcessBuffers( | 2995 ArrayBufferTracker::ProcessBuffers( |
2981 page, ArrayBufferTracker::kUpdateForwardedRemoveOthers); | 2996 page, ArrayBufferTracker::kUpdateForwardedRemoveOthers); |
2982 DCHECK(success); | |
2983 break; | 2997 break; |
2984 case kPageNewToOld: | 2998 case kPageNewToOld: |
2985 success = collector_->VisitLiveObjects(page, &new_space_page_visitor, | 2999 success = collector_->VisitLiveObjects(page, &new_to_old_page_visitor_, |
2986 kKeepMarking); | 3000 kKeepMarking); |
| 3001 DCHECK(success); |
| 3002 new_to_old_page_visitor_.account_moved_bytes(page->LiveBytes()); |
2987 // ArrayBufferTracker will be updated during sweeping. | 3003 // ArrayBufferTracker will be updated during sweeping. |
2988 DCHECK(success); | |
2989 break; | 3004 break; |
2990 case kPageNewToNew: | 3005 case kPageNewToNew: |
2991 new_space_page_visitor.account_semispace_copied(page->LiveBytes()); | 3006 success = collector_->VisitLiveObjects(page, &new_to_new_page_visitor_, |
| 3007 kKeepMarking); |
| 3008 DCHECK(success); |
| 3009 new_to_new_page_visitor_.account_moved_bytes(page->LiveBytes()); |
2992 // ArrayBufferTracker will be updated during sweeping. | 3010 // ArrayBufferTracker will be updated during sweeping. |
2993 success = true; | |
2994 break; | 3011 break; |
2995 case kObjectsOldToOld: | 3012 case kObjectsOldToOld: |
2996 success = collector_->VisitLiveObjects(page, &old_space_visitor_, | 3013 success = collector_->VisitLiveObjects(page, &old_space_visitor_, |
2997 kClearMarkbits); | 3014 kClearMarkbits); |
2998 if (!success) { | 3015 if (!success) { |
2999 // Aborted compaction page. We have to record slots here, since we | 3016 // Aborted compaction page. We have to record slots here, since we |
3000 // might not have recorded them in first place. | 3017 // might not have recorded them in first place. |
3001 // Note: We mark the page as aborted here to be able to record slots | 3018 // Note: We mark the page as aborted here to be able to record slots |
3002 // for code objects in |RecordMigratedSlotVisitor|. | 3019 // for code objects in |RecordMigratedSlotVisitor|. |
3003 page->SetFlag(Page::COMPACTION_WAS_ABORTED); | 3020 page->SetFlag(Page::COMPACTION_WAS_ABORTED); |
3004 EvacuateRecordOnlyVisitor record_visitor(collector_->heap()); | 3021 EvacuateRecordOnlyVisitor record_visitor(collector_->heap()); |
3005 success = | 3022 success = |
3006 collector_->VisitLiveObjects(page, &record_visitor, kKeepMarking); | 3023 collector_->VisitLiveObjects(page, &record_visitor, kKeepMarking); |
3007 ArrayBufferTracker::ProcessBuffers( | 3024 ArrayBufferTracker::ProcessBuffers( |
3008 page, ArrayBufferTracker::kUpdateForwardedKeepOthers); | 3025 page, ArrayBufferTracker::kUpdateForwardedKeepOthers); |
3009 DCHECK(success); | 3026 DCHECK(success); |
3010 // We need to return failure here to indicate that we want this page | 3027 // We need to return failure here to indicate that we want this page |
3011 // added to the sweeper. | 3028 // added to the sweeper. |
3012 success = false; | 3029 success = false; |
3013 } else { | 3030 } else { |
3014 ArrayBufferTracker::ProcessBuffers( | 3031 ArrayBufferTracker::ProcessBuffers( |
3015 page, ArrayBufferTracker::kUpdateForwardedRemoveOthers); | 3032 page, ArrayBufferTracker::kUpdateForwardedRemoveOthers); |
3016 } | 3033 } |
3017 break; | 3034 break; |
3018 default: | |
3019 UNREACHABLE(); | |
3020 } | 3035 } |
3021 } | 3036 } |
3022 ReportCompactionProgress(evacuation_time, saved_live_bytes); | 3037 ReportCompactionProgress(evacuation_time, saved_live_bytes); |
3023 if (FLAG_trace_evacuation) { | 3038 if (FLAG_trace_evacuation) { |
3024 PrintIsolate(heap->isolate(), | 3039 PrintIsolate(heap->isolate(), |
3025 "evacuation[%p]: page=%p new_space=%d " | 3040 "evacuation[%p]: page=%p new_space=%d " |
3026 "page_evacuation=%d executable=%d contains_age_mark=%d " | 3041 "page_evacuation=%d executable=%d contains_age_mark=%d " |
3027 "live_bytes=%d time=%f\n", | 3042 "live_bytes=%d time=%f\n", |
3028 static_cast<void*>(this), static_cast<void*>(page), | 3043 static_cast<void*>(this), static_cast<void*>(page), |
3029 page->InNewSpace(), | 3044 page->InNewSpace(), |
3030 page->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION) || | 3045 page->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION) || |
3031 page->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION), | 3046 page->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION), |
3032 page->IsFlagSet(MemoryChunk::IS_EXECUTABLE), | 3047 page->IsFlagSet(MemoryChunk::IS_EXECUTABLE), |
3033 page->Contains(heap->new_space()->age_mark()), | 3048 page->Contains(heap->new_space()->age_mark()), |
3034 saved_live_bytes, evacuation_time); | 3049 saved_live_bytes, evacuation_time); |
3035 } | 3050 } |
3036 return success; | 3051 return success; |
3037 } | 3052 } |
3038 | 3053 |
3039 void MarkCompactCollector::Evacuator::Finalize() { | 3054 void MarkCompactCollector::Evacuator::Finalize() { |
3040 heap()->old_space()->MergeCompactionSpace(compaction_spaces_.Get(OLD_SPACE)); | 3055 heap()->old_space()->MergeCompactionSpace(compaction_spaces_.Get(OLD_SPACE)); |
3041 heap()->code_space()->MergeCompactionSpace( | 3056 heap()->code_space()->MergeCompactionSpace( |
3042 compaction_spaces_.Get(CODE_SPACE)); | 3057 compaction_spaces_.Get(CODE_SPACE)); |
3043 heap()->tracer()->AddCompactionEvent(duration_, bytes_compacted_); | 3058 heap()->tracer()->AddCompactionEvent(duration_, bytes_compacted_); |
3044 heap()->IncrementPromotedObjectsSize(new_space_visitor_.promoted_size() + | 3059 heap()->IncrementPromotedObjectsSize(new_space_visitor_.promoted_size() + |
3045 new_space_page_visitor.promoted_size()); | 3060 new_to_old_page_visitor_.moved_bytes()); |
3046 heap()->IncrementSemiSpaceCopiedObjectSize( | 3061 heap()->IncrementSemiSpaceCopiedObjectSize( |
3047 new_space_visitor_.semispace_copied_size() + | 3062 new_space_visitor_.semispace_copied_size() + |
3048 new_space_page_visitor.semispace_copied_size()); | 3063 new_to_new_page_visitor_.moved_bytes()); |
3049 heap()->IncrementYoungSurvivorsCounter( | 3064 heap()->IncrementYoungSurvivorsCounter( |
3050 new_space_visitor_.promoted_size() + | 3065 new_space_visitor_.promoted_size() + |
3051 new_space_visitor_.semispace_copied_size() + | 3066 new_space_visitor_.semispace_copied_size() + |
3052 new_space_page_visitor.promoted_size() + | 3067 new_to_old_page_visitor_.moved_bytes() + |
3053 new_space_page_visitor.semispace_copied_size()); | 3068 new_to_new_page_visitor_.moved_bytes()); |
3054 heap()->MergeAllocationSitePretenuringFeedback(local_pretenuring_feedback_); | 3069 heap()->MergeAllocationSitePretenuringFeedback(local_pretenuring_feedback_); |
3055 } | 3070 } |
3056 | 3071 |
3057 int MarkCompactCollector::NumberOfParallelCompactionTasks(int pages, | 3072 int MarkCompactCollector::NumberOfParallelCompactionTasks(int pages, |
3058 intptr_t live_bytes) { | 3073 intptr_t live_bytes) { |
3059 if (!FLAG_parallel_compaction) return 1; | 3074 if (!FLAG_parallel_compaction) return 1; |
3060 // Compute the number of needed tasks based on a target compaction time, the | 3075 // Compute the number of needed tasks based on a target compaction time, the |
3061 // profiled compaction speed and marked live memory. | 3076 // profiled compaction speed and marked live memory. |
3062 // | 3077 // |
3063 // The number of parallel compaction tasks is limited by: | 3078 // The number of parallel compaction tasks is limited by: |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3140 } | 3155 } |
3141 | 3156 |
3142 const bool reduce_memory = heap()->ShouldReduceMemory(); | 3157 const bool reduce_memory = heap()->ShouldReduceMemory(); |
3143 const Address age_mark = heap()->new_space()->age_mark(); | 3158 const Address age_mark = heap()->new_space()->age_mark(); |
3144 for (Page* page : newspace_evacuation_candidates_) { | 3159 for (Page* page : newspace_evacuation_candidates_) { |
3145 live_bytes += page->LiveBytes(); | 3160 live_bytes += page->LiveBytes(); |
3146 if (!reduce_memory && !page->NeverEvacuate() && | 3161 if (!reduce_memory && !page->NeverEvacuate() && |
3147 (page->LiveBytes() > Evacuator::PageEvacuationThreshold()) && | 3162 (page->LiveBytes() > Evacuator::PageEvacuationThreshold()) && |
3148 !page->Contains(age_mark)) { | 3163 !page->Contains(age_mark)) { |
3149 if (page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK)) { | 3164 if (page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK)) { |
3150 EvacuateNewSpacePageVisitor::MoveToOldSpace(page, heap()->old_space()); | 3165 EvacuateNewSpacePageVisitor<NEW_TO_OLD>::Move(page); |
3151 } else { | 3166 } else { |
3152 EvacuateNewSpacePageVisitor::MoveToToSpace(page); | 3167 EvacuateNewSpacePageVisitor<NEW_TO_NEW>::Move(page); |
3153 } | 3168 } |
3154 } | 3169 } |
3155 | 3170 |
3156 job.AddPage(page, &abandoned_pages); | 3171 job.AddPage(page, &abandoned_pages); |
3157 } | 3172 } |
3158 DCHECK_GE(job.NumberOfPages(), 1); | 3173 DCHECK_GE(job.NumberOfPages(), 1); |
3159 | 3174 |
3160 // Used for trace summary. | 3175 // Used for trace summary. |
3161 double compaction_speed = 0; | 3176 double compaction_speed = 0; |
3162 if (FLAG_trace_evacuation) { | 3177 if (FLAG_trace_evacuation) { |
(...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3921 // The target is always in old space, we don't have to record the slot in | 3936 // The target is always in old space, we don't have to record the slot in |
3922 // the old-to-new remembered set. | 3937 // the old-to-new remembered set. |
3923 DCHECK(!heap()->InNewSpace(target)); | 3938 DCHECK(!heap()->InNewSpace(target)); |
3924 RecordRelocSlot(host, &rinfo, target); | 3939 RecordRelocSlot(host, &rinfo, target); |
3925 } | 3940 } |
3926 } | 3941 } |
3927 } | 3942 } |
3928 | 3943 |
3929 } // namespace internal | 3944 } // namespace internal |
3930 } // namespace v8 | 3945 } // namespace v8 |
OLD | NEW |