5 #include "src/heap/scavenger.h" 7 #include "src/heap/array-buffer-collector.h" 8 #include "src/heap/barrier.h" 9 #include "src/heap/gc-tracer.h" 10 #include "src/heap/heap-inl.h" 11 #include "src/heap/item-parallel-job.h" 12 #include "src/heap/mark-compact-inl.h" 13 #include "src/heap/objects-visiting-inl.h" 14 #include "src/heap/scavenger-inl.h" 15 #include "src/heap/sweeper.h" 16 #include "src/objects-body-descriptors-inl.h" 17 #include "src/utils-inl.h" 27 void Process(
Scavenger* scavenger) { scavenger->ScavengePage(chunk_); }
38 scavenger_(scavenger),
41 void RunInParallel()
final {
44 GCTracer::BackgroundScope::SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL);
45 double scavenging_time = 0.0;
50 while ((item = GetItem<PageScavengingItem>()) !=
nullptr) {
51 item->Process(scavenger_);
55 scavenger_->Process(barrier_);
56 }
while (!barrier_->Wait());
57 scavenger_->Process();
59 if (FLAG_trace_parallel_scavenge) {
60 PrintIsolate(heap_->isolate(),
61 "scavenge[%p]: time=%.2f copied=%zu promoted=%zu\n",
62 static_cast<void*
>(
this), scavenging_time,
63 scavenger_->bytes_copied(), scavenger_->bytes_promoted());
77 : heap_(heap), scavenger_(scavenger), record_slots_(record_slots) {}
81 for (
ObjectSlot slot = start; slot < end; ++slot) {
83 DCHECK(!HasWeakHeapObjectTag(target));
84 if (target->IsHeapObject()) {
97 if (target->GetHeapObject(&heap_object)) {
105 scavenger_->PageMemoryFence(MaybeObject::FromObject(target));
107 if (Heap::InFromSpace(target)) {
108 SlotCallbackResult result = scavenger_->ScavengeObject(slot, target);
109 bool success = (*slot)->GetHeapObject(&target);
113 if (result == KEEP_SLOT) {
114 SLOW_DCHECK(target->IsHeapObject());
118 SLOW_DCHECK(!MarkCompactCollector::IsOnEvacuationCandidate(
119 HeapObject::cast(target)));
120 }
else if (record_slots_ && MarkCompactCollector::IsOnEvacuationCandidate(
121 HeapObject::cast(target))) {
122 heap_->mark_compact_collector()->RecordSlot(host,
ObjectSlot(slot),
130 const bool record_slots_;
134 return Heap::InFromSpace(*p) &&
135 !HeapObject::cast(*p)->map_word().IsForwardingAddress();
141 if (!Heap::InFromSpace(
object)) {
145 MapWord map_word = HeapObject::cast(
object)->map_word();
146 if (map_word.IsForwardingAddress()) {
147 return map_word.ToForwardingAddress();
153 ScavengerCollector::ScavengerCollector(
Heap* heap)
154 : isolate_(heap->isolate()), heap_(heap), parallel_scavenge_semaphore_(0) {}
156 void ScavengerCollector::CollectGarbage() {
157 DCHECK(surviving_new_large_objects_.empty());
158 ItemParallelJob job(isolate_->cancelable_task_manager(),
159 ¶llel_scavenge_semaphore_);
160 const int kMainThreadId = 0;
161 Scavenger* scavengers[kMaxScavengerTasks];
162 const bool is_logging = isolate_->LogObjectRelocation();
163 const int num_scavenge_tasks = NumberOfScavengeTasks();
164 OneshotBarrier barrier(base::TimeDelta::FromMilliseconds(kMaxWaitTimeMs));
165 Scavenger::CopiedList copied_list(num_scavenge_tasks);
166 Scavenger::PromotionList promotion_list(num_scavenge_tasks);
167 for (
int i = 0;
i < num_scavenge_tasks;
i++) {
168 scavengers[
i] =
new Scavenger(
this, heap_, is_logging, &copied_list,
170 job.AddTask(
new ScavengingTask(heap_, scavengers[
i], &barrier));
174 Sweeper* sweeper = heap_->mark_compact_collector()->sweeper();
176 Sweeper::PauseOrCompleteScope pause_scope(sweeper);
182 Sweeper::FilterSweepingPagesScope filter_scope(sweeper, pause_scope);
183 filter_scope.FilterOldSpaceSweepingPages(
184 [](Page* page) {
return !page->ContainsSlots<OLD_TO_NEW>(); });
185 RememberedSet<OLD_TO_NEW>::IterateMemoryChunks(
186 heap_, [&job](MemoryChunk* chunk) {
187 job.AddItem(
new PageScavengingItem(chunk));
190 RootScavengeVisitor root_scavenge_visitor(scavengers[kMainThreadId]);
196 GCTracer::Scope::SCAVENGER_SCAVENGE_WEAK_GLOBAL_HANDLES_IDENTIFY);
197 isolate_->global_handles()->IdentifyWeakUnmodifiedObjects(
198 &JSObject::IsUnmodifiedApiObject);
202 TRACE_GC(heap_->tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE_ROOTS);
203 heap_->IterateRoots(&root_scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
207 TRACE_GC(heap_->tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE_PARALLEL);
208 job.Run(isolate_->async_counters());
209 DCHECK(copied_list.IsEmpty());
210 DCHECK(promotion_list.IsEmpty());
214 TRACE_GC(heap_->tracer(),
215 GCTracer::Scope::SCAVENGER_SCAVENGE_WEAK_GLOBAL_HANDLES_PROCESS);
216 isolate_->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending(
217 &IsUnscavengedHeapObject);
218 isolate_->global_handles()
219 ->IterateNewSpaceWeakUnmodifiedRootsForFinalizers(
220 &root_scavenge_visitor);
221 scavengers[kMainThreadId]->Process();
223 DCHECK(copied_list.IsEmpty());
224 DCHECK(promotion_list.IsEmpty());
225 isolate_->global_handles()
226 ->IterateNewSpaceWeakUnmodifiedRootsForPhantomHandles(
227 &root_scavenge_visitor, &IsUnscavengedHeapObject);
232 TRACE_GC(heap_->tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE_FINALIZE);
234 for (
int i = 0;
i < num_scavenge_tasks;
i++) {
235 scavengers[
i]->Finalize();
236 delete scavengers[
i];
239 HandleSurvivingNewLargeObjects();
245 TRACE_GC(heap_->tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE_UPDATE_REFS);
246 heap_->UpdateNewSpaceReferencesInExternalStringTable(
247 &Heap::UpdateNewSpaceReferenceInExternalStringTableEntry);
249 heap_->incremental_marking()->UpdateMarkingWorklistAfterScavenge();
252 if (FLAG_concurrent_marking) {
256 PageRange(heap_->new_space()->from_space().first_page(),
nullptr)) {
257 heap_->concurrent_marking()->ClearLiveness(p);
261 ScavengeWeakObjectRetainer weak_object_retainer;
262 heap_->ProcessYoungWeakReferences(&weak_object_retainer);
265 heap_->new_space_->set_age_mark(heap_->new_space()->top());
268 TRACE_GC(heap_->tracer(), GCTracer::Scope::SCAVENGER_PROCESS_ARRAY_BUFFERS);
269 ArrayBufferTracker::PrepareToFreeDeadInNewSpace(heap_);
271 heap_->array_buffer_collector()->FreeAllocations();
276 heap_->new_lo_space()->FreeAllObjects();
278 RememberedSet<OLD_TO_NEW>::IterateMemoryChunks(heap_, [](MemoryChunk* chunk) {
279 if (chunk->SweepingDone()) {
280 RememberedSet<OLD_TO_NEW>::FreeEmptyBuckets(chunk);
282 RememberedSet<OLD_TO_NEW>::PreFreeEmptyBuckets(chunk);
287 heap_->IncrementYoungSurvivorsCounter(heap_->SurvivedNewSpaceObjectSize());
290 void ScavengerCollector::HandleSurvivingNewLargeObjects() {
291 for (SurvivingNewLargeObjectMapEntry update_info :
292 surviving_new_large_objects_) {
293 HeapObject*
object = update_info.first;
294 Map map = update_info.second;
297 object->set_map_word(MapWord::FromMap(map));
298 LargePage* page = LargePage::FromHeapObject(
object);
299 heap_->lo_space()->PromoteNewLargeObject(page);
301 surviving_new_large_objects_.clear();
304 void ScavengerCollector::MergeSurvivingNewLargeObjects(
305 const SurvivingNewLargeObjectsMap& objects) {
306 for (SurvivingNewLargeObjectMapEntry
object : objects) {
307 bool success = surviving_new_large_objects_.insert(
object).second;
313 int ScavengerCollector::NumberOfScavengeTasks() {
314 if (!FLAG_parallel_scavenge)
return 1;
315 const int num_scavenge_tasks =
316 static_cast<int>(heap_->new_space()->TotalCapacity()) / MB;
317 static int num_cores = V8::GetCurrentPlatform()->NumberOfWorkerThreads() + 1;
319 Max(1, Min(Min(num_scavenge_tasks, kMaxScavengerTasks), num_cores));
320 if (!heap_->CanExpandOldGeneration(
321 static_cast<size_t>(tasks * Page::kPageSize))) {
328 Scavenger::Scavenger(ScavengerCollector* collector, Heap* heap,
bool is_logging,
329 CopiedList* copied_list, PromotionList* promotion_list,
331 : collector_(collector),
333 promotion_list_(promotion_list, task_id),
334 copied_list_(copied_list, task_id),
335 local_pretenuring_feedback_(kInitialLocalPretenuringFeedbackCapacity),
339 is_logging_(is_logging),
340 is_incremental_marking_(heap->incremental_marking()->IsMarking()),
341 is_compacting_(heap->incremental_marking()->IsCompacting()) {}
343 void Scavenger::IterateAndScavengePromotedObject(HeapObject* target, Map map,
351 const bool record_slots =
353 heap()->incremental_marking()->atomic_marking_state()->IsBlack(target);
354 IterateAndScavengePromotedObjectsVisitor visitor(heap(),
this, record_slots);
355 target->IterateBodyFast(map, size, &visitor);
358 void Scavenger::AddPageToSweeperIfNecessary(MemoryChunk* page) {
359 AllocationSpace space = page->owner()->identity();
360 if ((space == OLD_SPACE) && !page->SweepingDone()) {
361 heap()->mark_compact_collector()->sweeper()->AddPage(
362 space, reinterpret_cast<Page*>(page),
363 Sweeper::READD_TEMPORARY_REMOVED_PAGE);
367 void Scavenger::ScavengePage(MemoryChunk* page) {
368 CodePageMemoryModificationScope memory_modification_scope(page);
369 RememberedSet<OLD_TO_NEW>::Iterate(page,
370 [
this](MaybeObjectSlot addr) {
371 return CheckAndScavengeObject(heap_,
374 SlotSet::KEEP_EMPTY_BUCKETS);
375 RememberedSet<OLD_TO_NEW>::IterateTyped(
376 page, [
this](SlotType type, Address host_addr, Address addr) {
377 return UpdateTypedSlotHelper::UpdateTypedSlot(
378 heap_, type, addr, [
this](MaybeObjectSlot slot) {
379 return CheckAndScavengeObject(heap(), slot);
383 AddPageToSweeperIfNecessary(page);
386 void Scavenger::Process(OneshotBarrier* barrier) {
387 ScavengeVisitor scavenge_visitor(
this);
389 const bool have_barrier = barrier !=
nullptr;
394 ObjectAndSize object_and_size;
395 while (promotion_list_.ShouldEagerlyProcessPromotionList() &&
396 copied_list_.Pop(&object_and_size)) {
397 scavenge_visitor.Visit(object_and_size.first);
399 if (have_barrier && ((++objects % kInterruptThreshold) == 0)) {
400 if (!copied_list_.IsGlobalPoolEmpty()) {
401 barrier->NotifyAll();
406 struct PromotionListEntry entry;
407 while (promotion_list_.Pop(&entry)) {
408 HeapObject* target = entry.heap_object;
409 DCHECK(!target->IsMap());
410 IterateAndScavengePromotedObject(target, entry.map, entry.size);
412 if (have_barrier && ((++objects % kInterruptThreshold) == 0)) {
413 if (!promotion_list_.IsGlobalPoolEmpty()) {
414 barrier->NotifyAll();
421 void Scavenger::Finalize() {
422 heap()->MergeAllocationSitePretenuringFeedback(local_pretenuring_feedback_);
423 heap()->IncrementSemiSpaceCopiedObjectSize(copied_size_);
424 heap()->IncrementPromotedObjectsSize(promoted_size_);
425 collector_->MergeSurvivingNewLargeObjects(surviving_new_large_objects_);
426 allocator_.Finalize();
429 void RootScavengeVisitor::VisitRootPointer(Root root,
const char* description,
431 DCHECK(!HasWeakHeapObjectTag(*p));
435 void RootScavengeVisitor::VisitRootPointers(Root root,
const char* description,
436 ObjectSlot start, ObjectSlot end) {
438 for (ObjectSlot p = start; p < end; ++p) ScavengePointer(p);
441 void RootScavengeVisitor::ScavengePointer(ObjectSlot p) {
443 DCHECK(!HasWeakHeapObjectTag(
object));
444 if (!Heap::InNewSpace(
object))
return;
446 scavenger_->ScavengeObject(HeapObjectSlot(p),
447 reinterpret_cast<HeapObject*>(
object));
450 RootScavengeVisitor::RootScavengeVisitor(Scavenger* scavenger)
451 : scavenger_(scavenger) {}
453 ScavengeVisitor::ScavengeVisitor(Scavenger* scavenger)
454 : scavenger_(scavenger) {}