1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/heap/scavenger.h"
6
7 #include "src/heap/barrier.h"
8 #include "src/heap/heap-inl.h"
9 #include "src/heap/mark-compact-inl.h"
10 #include "src/heap/objects-visiting-inl.h"
11 #include "src/heap/scavenger-inl.h"
12 #include "src/heap/sweeper.h"
13 #include "src/objects-body-descriptors-inl.h"
14
15 namespace v8 {
16 namespace internal {
17
18 class IterateAndScavengePromotedObjectsVisitor final : public ObjectVisitor {
19 public:
IterateAndScavengePromotedObjectsVisitor(Heap * heap,Scavenger * scavenger,bool record_slots)20 IterateAndScavengePromotedObjectsVisitor(Heap* heap, Scavenger* scavenger,
21 bool record_slots)
22 : heap_(heap), scavenger_(scavenger), record_slots_(record_slots) {}
23
VisitPointers(HeapObject * host,Object ** start,Object ** end)24 inline void VisitPointers(HeapObject* host, Object** start,
25 Object** end) final {
26 for (Object** slot = start; slot < end; ++slot) {
27 Object* target = *slot;
28 DCHECK(!HasWeakHeapObjectTag(target));
29 if (target->IsHeapObject()) {
30 HandleSlot(host, reinterpret_cast<Address>(slot),
31 HeapObject::cast(target));
32 }
33 }
34 }
35
VisitPointers(HeapObject * host,MaybeObject ** start,MaybeObject ** end)36 inline void VisitPointers(HeapObject* host, MaybeObject** start,
37 MaybeObject** end) final {
38 // Treat weak references as strong. TODO(marja): Proper weakness handling in
39 // the young generation.
40 for (MaybeObject** slot = start; slot < end; ++slot) {
41 MaybeObject* target = *slot;
42 HeapObject* heap_object;
43 if (target->ToStrongOrWeakHeapObject(&heap_object)) {
44 HandleSlot(host, reinterpret_cast<Address>(slot), heap_object);
45 }
46 }
47 }
48
HandleSlot(HeapObject * host,Address slot_address,HeapObject * target)49 inline void HandleSlot(HeapObject* host, Address slot_address,
50 HeapObject* target) {
51 HeapObjectReference** slot =
52 reinterpret_cast<HeapObjectReference**>(slot_address);
53 scavenger_->PageMemoryFence(reinterpret_cast<MaybeObject*>(target));
54
55 if (Heap::InFromSpace(target)) {
56 scavenger_->ScavengeObject(slot, target);
57 bool success = (*slot)->ToStrongOrWeakHeapObject(&target);
58 USE(success);
59 DCHECK(success);
60 scavenger_->PageMemoryFence(reinterpret_cast<MaybeObject*>(target));
61
62 if (Heap::InNewSpace(target)) {
63 SLOW_DCHECK(target->IsHeapObject());
64 SLOW_DCHECK(Heap::InToSpace(target));
65 RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot_address),
66 slot_address);
67 }
68 SLOW_DCHECK(!MarkCompactCollector::IsOnEvacuationCandidate(
69 HeapObject::cast(target)));
70 } else if (record_slots_ && MarkCompactCollector::IsOnEvacuationCandidate(
71 HeapObject::cast(target))) {
72 heap_->mark_compact_collector()->RecordSlot(host, slot, target);
73 }
74 }
75
76 private:
77 Heap* const heap_;
78 Scavenger* const scavenger_;
79 const bool record_slots_;
80 };
81
Scavenger(Heap * heap,bool is_logging,CopiedList * copied_list,PromotionList * promotion_list,int task_id)82 Scavenger::Scavenger(Heap* heap, bool is_logging, CopiedList* copied_list,
83 PromotionList* promotion_list, int task_id)
84 : heap_(heap),
85 promotion_list_(promotion_list, task_id),
86 copied_list_(copied_list, task_id),
87 local_pretenuring_feedback_(kInitialLocalPretenuringFeedbackCapacity),
88 copied_size_(0),
89 promoted_size_(0),
90 allocator_(heap),
91 is_logging_(is_logging),
92 is_incremental_marking_(heap->incremental_marking()->IsMarking()),
93 is_compacting_(heap->incremental_marking()->IsCompacting()) {}
94
IterateAndScavengePromotedObject(HeapObject * target,int size)95 void Scavenger::IterateAndScavengePromotedObject(HeapObject* target, int size) {
96 // We are not collecting slots on new space objects during mutation thus we
97 // have to scan for pointers to evacuation candidates when we promote
98 // objects. But we should not record any slots in non-black objects. Grey
99 // object's slots would be rescanned. White object might not survive until
100 // the end of collection it would be a violation of the invariant to record
101 // its slots.
102 const bool record_slots =
103 is_compacting_ &&
104 heap()->incremental_marking()->atomic_marking_state()->IsBlack(target);
105 IterateAndScavengePromotedObjectsVisitor visitor(heap(), this, record_slots);
106 target->IterateBodyFast(target->map(), size, &visitor);
107 }
108
AddPageToSweeperIfNecessary(MemoryChunk * page)109 void Scavenger::AddPageToSweeperIfNecessary(MemoryChunk* page) {
110 AllocationSpace space = page->owner()->identity();
111 if ((space == OLD_SPACE) && !page->SweepingDone()) {
112 heap()->mark_compact_collector()->sweeper()->AddPage(
113 space, reinterpret_cast<Page*>(page),
114 Sweeper::READD_TEMPORARY_REMOVED_PAGE);
115 }
116 }
117
ScavengePage(MemoryChunk * page)118 void Scavenger::ScavengePage(MemoryChunk* page) {
119 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.gc"), "Scavenger::ScavengePage");
120 CodePageMemoryModificationScope memory_modification_scope(page);
121 RememberedSet<OLD_TO_NEW>::Iterate(
122 page,
123 [this](Address addr) { return CheckAndScavengeObject(heap_, addr); },
124 SlotSet::KEEP_EMPTY_BUCKETS);
125 RememberedSet<OLD_TO_NEW>::IterateTyped(
126 page, [this](SlotType type, Address host_addr, Address addr) {
127 return UpdateTypedSlotHelper::UpdateTypedSlot(
128 heap_, type, addr, [this](MaybeObject** addr) {
129 return CheckAndScavengeObject(heap(),
130 reinterpret_cast<Address>(addr));
131 });
132 });
133
134 AddPageToSweeperIfNecessary(page);
135 }
136
Process(OneshotBarrier * barrier)137 void Scavenger::Process(OneshotBarrier* barrier) {
138 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.gc"), "Scavenger::Process");
139 // Threshold when to switch processing the promotion list to avoid
140 // allocating too much backing store in the worklist.
141 const int kProcessPromotionListThreshold = kPromotionListSegmentSize / 2;
142 ScavengeVisitor scavenge_visitor(this);
143
144 const bool have_barrier = barrier != nullptr;
145 bool done;
146 size_t objects = 0;
147 do {
148 done = true;
149 ObjectAndSize object_and_size;
150 while ((promotion_list_.LocalPushSegmentSize() <
151 kProcessPromotionListThreshold) &&
152 copied_list_.Pop(&object_and_size)) {
153 scavenge_visitor.Visit(object_and_size.first);
154 done = false;
155 if (have_barrier && ((++objects % kInterruptThreshold) == 0)) {
156 if (!copied_list_.IsGlobalPoolEmpty()) {
157 barrier->NotifyAll();
158 }
159 }
160 }
161
162 while (promotion_list_.Pop(&object_and_size)) {
163 HeapObject* target = object_and_size.first;
164 int size = object_and_size.second;
165 DCHECK(!target->IsMap());
166 IterateAndScavengePromotedObject(target, size);
167 done = false;
168 if (have_barrier && ((++objects % kInterruptThreshold) == 0)) {
169 if (!promotion_list_.IsGlobalPoolEmpty()) {
170 barrier->NotifyAll();
171 }
172 }
173 }
174 } while (!done);
175 }
176
Finalize()177 void Scavenger::Finalize() {
178 heap()->MergeAllocationSitePretenuringFeedback(local_pretenuring_feedback_);
179 heap()->IncrementSemiSpaceCopiedObjectSize(copied_size_);
180 heap()->IncrementPromotedObjectsSize(promoted_size_);
181 allocator_.Finalize();
182 }
183
VisitRootPointer(Root root,const char * description,Object ** p)184 void RootScavengeVisitor::VisitRootPointer(Root root, const char* description,
185 Object** p) {
186 DCHECK(!HasWeakHeapObjectTag(*p));
187 ScavengePointer(p);
188 }
189
VisitRootPointers(Root root,const char * description,Object ** start,Object ** end)190 void RootScavengeVisitor::VisitRootPointers(Root root, const char* description,
191 Object** start, Object** end) {
192 // Copy all HeapObject pointers in [start, end)
193 for (Object** p = start; p < end; p++) ScavengePointer(p);
194 }
195
ScavengePointer(Object ** p)196 void RootScavengeVisitor::ScavengePointer(Object** p) {
197 Object* object = *p;
198 DCHECK(!HasWeakHeapObjectTag(object));
199 if (!Heap::InNewSpace(object)) return;
200
201 scavenger_->ScavengeObject(reinterpret_cast<HeapObjectReference**>(p),
202 reinterpret_cast<HeapObject*>(object));
203 }
204
RootScavengeVisitor(Scavenger * scavenger)205 RootScavengeVisitor::RootScavengeVisitor(Scavenger* scavenger)
206 : scavenger_(scavenger) {}
207
ScavengeVisitor(Scavenger * scavenger)208 ScavengeVisitor::ScavengeVisitor(Scavenger* scavenger)
209 : scavenger_(scavenger) {}
210
211 } // namespace internal
212 } // namespace v8
213