Home | History | Annotate | Download | only in heap
      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
      3 // found in the LICENSE file.
      4 
      5 #include "src/heap/mark-compact.h"
      6 
      7 #include "src/base/atomicops.h"
      8 #include "src/base/bits.h"
      9 #include "src/base/sys-info.h"
     10 #include "src/code-stubs.h"
     11 #include "src/compilation-cache.h"
     12 #include "src/deoptimizer.h"
     13 #include "src/execution.h"
     14 #include "src/frames-inl.h"
     15 #include "src/gdb-jit.h"
     16 #include "src/global-handles.h"
     17 #include "src/heap/array-buffer-tracker.h"
     18 #include "src/heap/gc-tracer.h"
     19 #include "src/heap/incremental-marking.h"
     20 #include "src/heap/mark-compact-inl.h"
     21 #include "src/heap/object-stats.h"
     22 #include "src/heap/objects-visiting-inl.h"
     23 #include "src/heap/objects-visiting.h"
     24 #include "src/heap/page-parallel-job.h"
     25 #include "src/heap/spaces-inl.h"
     26 #include "src/ic/ic.h"
     27 #include "src/ic/stub-cache.h"
     28 #include "src/tracing/tracing-category-observer.h"
     29 #include "src/utils-inl.h"
     30 #include "src/v8.h"
     31 #include "src/v8threads.h"
     32 
     33 namespace v8 {
     34 namespace internal {
     35 
     36 
     37 const char* Marking::kWhiteBitPattern = "00";
     38 const char* Marking::kBlackBitPattern = "11";
     39 const char* Marking::kGreyBitPattern = "10";
     40 const char* Marking::kImpossibleBitPattern = "01";
     41 
     42 // The following has to hold in order for {ObjectMarking::MarkBitFrom} to not
     43 // produce invalid {kImpossibleBitPattern} in the marking bitmap by overlapping.
     44 STATIC_ASSERT(Heap::kMinObjectSizeInWords >= 2);
     45 
     46 
     47 // -------------------------------------------------------------------------
     48 // MarkCompactCollector
     49 
     50 MarkCompactCollector::MarkCompactCollector(Heap* heap)
     51     :  // NOLINT
     52       heap_(heap),
     53       page_parallel_job_semaphore_(0),
     54 #ifdef DEBUG
     55       state_(IDLE),
     56 #endif
     57       was_marked_incrementally_(false),
     58       evacuation_(false),
     59       compacting_(false),
     60       black_allocation_(false),
     61       have_code_to_deoptimize_(false),
     62       marking_deque_(heap),
     63       code_flusher_(nullptr),
     64       sweeper_(heap) {
     65 }
     66 
     67 #ifdef VERIFY_HEAP
     68 class VerifyMarkingVisitor : public ObjectVisitor {
     69  public:
     70   void VisitPointers(Object** start, Object** end) override {
     71     for (Object** current = start; current < end; current++) {
     72       if ((*current)->IsHeapObject()) {
     73         HeapObject* object = HeapObject::cast(*current);
     74         CHECK(ObjectMarking::IsBlackOrGrey(object));
     75       }
     76     }
     77   }
     78 
     79   void VisitEmbeddedPointer(RelocInfo* rinfo) override {
     80     DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
     81     if (!rinfo->host()->IsWeakObject(rinfo->target_object())) {
     82       Object* p = rinfo->target_object();
     83       VisitPointer(&p);
     84     }
     85   }
     86 
     87   void VisitCell(RelocInfo* rinfo) override {
     88     Code* code = rinfo->host();
     89     DCHECK(rinfo->rmode() == RelocInfo::CELL);
     90     if (!code->IsWeakObject(rinfo->target_cell())) {
     91       ObjectVisitor::VisitCell(rinfo);
     92     }
     93   }
     94 };
     95 
     96 
     97 static void VerifyMarking(Heap* heap, Address bottom, Address top) {
     98   VerifyMarkingVisitor visitor;
     99   HeapObject* object;
    100   Address next_object_must_be_here_or_later = bottom;
    101   for (Address current = bottom; current < top;) {
    102     object = HeapObject::FromAddress(current);
    103     // One word fillers at the end of a black area can be grey.
    104     if (ObjectMarking::IsBlackOrGrey(object) &&
    105         object->map() != heap->one_pointer_filler_map()) {
    106       CHECK(ObjectMarking::IsBlack(object));
    107       CHECK(current >= next_object_must_be_here_or_later);
    108       object->Iterate(&visitor);
    109       next_object_must_be_here_or_later = current + object->Size();
    110       // The object is either part of a black area of black allocation or a
    111       // regular black object
    112       Page* page = Page::FromAddress(current);
    113       CHECK(
    114           page->markbits()->AllBitsSetInRange(
    115               page->AddressToMarkbitIndex(current),
    116               page->AddressToMarkbitIndex(next_object_must_be_here_or_later)) ||
    117           page->markbits()->AllBitsClearInRange(
    118               page->AddressToMarkbitIndex(current + kPointerSize * 2),
    119               page->AddressToMarkbitIndex(next_object_must_be_here_or_later)));
    120       current = next_object_must_be_here_or_later;
    121     } else {
    122       current += kPointerSize;
    123     }
    124   }
    125 }
    126 
    127 static void VerifyMarking(NewSpace* space) {
    128   Address end = space->top();
    129   // The bottom position is at the start of its page. Allows us to use
    130   // page->area_start() as start of range on all pages.
    131   CHECK_EQ(space->bottom(), Page::FromAddress(space->bottom())->area_start());
    132 
    133   PageRange range(space->bottom(), end);
    134   for (auto it = range.begin(); it != range.end();) {
    135     Page* page = *(it++);
    136     Address limit = it != range.end() ? page->area_end() : end;
    137     CHECK(limit == end || !page->Contains(end));
    138     VerifyMarking(space->heap(), page->area_start(), limit);
    139   }
    140 }
    141 
    142 
    143 static void VerifyMarking(PagedSpace* space) {
    144   for (Page* p : *space) {
    145     VerifyMarking(space->heap(), p->area_start(), p->area_end());
    146   }
    147 }
    148 
    149 
    150 static void VerifyMarking(Heap* heap) {
    151   VerifyMarking(heap->old_space());
    152   VerifyMarking(heap->code_space());
    153   VerifyMarking(heap->map_space());
    154   VerifyMarking(heap->new_space());
    155 
    156   VerifyMarkingVisitor visitor;
    157 
    158   LargeObjectIterator it(heap->lo_space());
    159   for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
    160     if (ObjectMarking::IsBlackOrGrey(obj)) {
    161       obj->Iterate(&visitor);
    162     }
    163   }
    164 
    165   heap->IterateStrongRoots(&visitor, VISIT_ONLY_STRONG);
    166 }
    167 
    168 
    169 class VerifyEvacuationVisitor : public ObjectVisitor {
    170  public:
    171   void VisitPointers(Object** start, Object** end) override {
    172     for (Object** current = start; current < end; current++) {
    173       if ((*current)->IsHeapObject()) {
    174         HeapObject* object = HeapObject::cast(*current);
    175         CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(object));
    176       }
    177     }
    178   }
    179 };
    180 
    181 
    182 static void VerifyEvacuation(Page* page) {
    183   VerifyEvacuationVisitor visitor;
    184   HeapObjectIterator iterator(page);
    185   for (HeapObject* heap_object = iterator.Next(); heap_object != NULL;
    186        heap_object = iterator.Next()) {
    187     // We skip free space objects.
    188     if (!heap_object->IsFiller()) {
    189       heap_object->Iterate(&visitor);
    190     }
    191   }
    192 }
    193 
    194 
    195 static void VerifyEvacuation(NewSpace* space) {
    196   VerifyEvacuationVisitor visitor;
    197   PageRange range(space->bottom(), space->top());
    198   for (auto it = range.begin(); it != range.end();) {
    199     Page* page = *(it++);
    200     Address current = page->area_start();
    201     Address limit = it != range.end() ? page->area_end() : space->top();
    202     CHECK(limit == space->top() || !page->Contains(space->top()));
    203     while (current < limit) {
    204       HeapObject* object = HeapObject::FromAddress(current);
    205       object->Iterate(&visitor);
    206       current += object->Size();
    207     }
    208   }
    209 }
    210 
    211 
    212 static void VerifyEvacuation(Heap* heap, PagedSpace* space) {
    213   if (FLAG_use_allocation_folding && (space == heap->old_space())) {
    214     return;
    215   }
    216   for (Page* p : *space) {
    217     if (p->IsEvacuationCandidate()) continue;
    218     VerifyEvacuation(p);
    219   }
    220 }
    221 
    222 
    223 static void VerifyEvacuation(Heap* heap) {
    224   VerifyEvacuation(heap, heap->old_space());
    225   VerifyEvacuation(heap, heap->code_space());
    226   VerifyEvacuation(heap, heap->map_space());
    227   VerifyEvacuation(heap->new_space());
    228 
    229   VerifyEvacuationVisitor visitor;
    230   heap->IterateStrongRoots(&visitor, VISIT_ALL);
    231 }
    232 #endif  // VERIFY_HEAP
    233 
    234 
    235 void MarkCompactCollector::SetUp() {
    236   DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
    237   DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
    238   DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
    239   DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
    240   marking_deque()->SetUp();
    241 
    242   if (FLAG_flush_code) {
    243     code_flusher_ = new CodeFlusher(isolate());
    244     if (FLAG_trace_code_flushing) {
    245       PrintF("[code-flushing is now on]\n");
    246     }
    247   }
    248 }
    249 
    250 
    251 void MarkCompactCollector::TearDown() {
    252   AbortCompaction();
    253   marking_deque()->TearDown();
    254   delete code_flusher_;
    255 }
    256 
    257 
    258 void MarkCompactCollector::AddEvacuationCandidate(Page* p) {
    259   DCHECK(!p->NeverEvacuate());
    260   p->MarkEvacuationCandidate();
    261   evacuation_candidates_.Add(p);
    262 }
    263 
    264 
    265 static void TraceFragmentation(PagedSpace* space) {
    266   int number_of_pages = space->CountTotalPages();
    267   intptr_t reserved = (number_of_pages * space->AreaSize());
    268   intptr_t free = reserved - space->SizeOfObjects();
    269   PrintF("[%s]: %d pages, %d (%.1f%%) free\n",
    270          AllocationSpaceName(space->identity()), number_of_pages,
    271          static_cast<int>(free), static_cast<double>(free) * 100 / reserved);
    272 }
    273 
    274 bool MarkCompactCollector::StartCompaction() {
    275   if (!compacting_) {
    276     DCHECK(evacuation_candidates_.length() == 0);
    277 
    278     CollectEvacuationCandidates(heap()->old_space());
    279 
    280     if (FLAG_compact_code_space) {
    281       CollectEvacuationCandidates(heap()->code_space());
    282     } else if (FLAG_trace_fragmentation) {
    283       TraceFragmentation(heap()->code_space());
    284     }
    285 
    286     if (FLAG_trace_fragmentation) {
    287       TraceFragmentation(heap()->map_space());
    288     }
    289 
    290     compacting_ = evacuation_candidates_.length() > 0;
    291   }
    292 
    293   return compacting_;
    294 }
    295 
    296 void MarkCompactCollector::CollectGarbage() {
    297   // Make sure that Prepare() has been called. The individual steps below will
    298   // update the state as they proceed.
    299   DCHECK(state_ == PREPARE_GC);
    300 
    301   MarkLiveObjects();
    302 
    303   DCHECK(heap_->incremental_marking()->IsStopped());
    304 
    305   ClearNonLiveReferences();
    306 
    307   RecordObjectStats();
    308 
    309 #ifdef VERIFY_HEAP
    310   if (FLAG_verify_heap) {
    311     VerifyMarking(heap_);
    312   }
    313 #endif
    314 
    315   StartSweepSpaces();
    316 
    317   EvacuateNewSpaceAndCandidates();
    318 
    319   Finish();
    320 }
    321 
    322 #ifdef VERIFY_HEAP
    323 void MarkCompactCollector::VerifyMarkbitsAreClean(PagedSpace* space) {
    324   for (Page* p : *space) {
    325     CHECK(p->markbits()->IsClean());
    326     CHECK_EQ(0, p->LiveBytes());
    327   }
    328 }
    329 
    330 
    331 void MarkCompactCollector::VerifyMarkbitsAreClean(NewSpace* space) {
    332   for (Page* p : PageRange(space->bottom(), space->top())) {
    333     CHECK(p->markbits()->IsClean());
    334     CHECK_EQ(0, p->LiveBytes());
    335   }
    336 }
    337 
    338 
    339 void MarkCompactCollector::VerifyMarkbitsAreClean() {
    340   VerifyMarkbitsAreClean(heap_->old_space());
    341   VerifyMarkbitsAreClean(heap_->code_space());
    342   VerifyMarkbitsAreClean(heap_->map_space());
    343   VerifyMarkbitsAreClean(heap_->new_space());
    344 
    345   LargeObjectIterator it(heap_->lo_space());
    346   for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
    347     CHECK(ObjectMarking::IsWhite(obj));
    348     CHECK_EQ(0, Page::FromAddress(obj->address())->LiveBytes());
    349   }
    350 }
    351 
    352 void MarkCompactCollector::VerifyWeakEmbeddedObjectsInCode() {
    353   HeapObjectIterator code_iterator(heap()->code_space());
    354   for (HeapObject* obj = code_iterator.Next(); obj != NULL;
    355        obj = code_iterator.Next()) {
    356     Code* code = Code::cast(obj);
    357     if (!code->is_optimized_code()) continue;
    358     if (WillBeDeoptimized(code)) continue;
    359     code->VerifyEmbeddedObjectsDependency();
    360   }
    361 }
    362 
    363 
    364 void MarkCompactCollector::VerifyOmittedMapChecks() {
    365   HeapObjectIterator iterator(heap()->map_space());
    366   for (HeapObject* obj = iterator.Next(); obj != NULL; obj = iterator.Next()) {
    367     Map* map = Map::cast(obj);
    368     map->VerifyOmittedMapChecks();
    369   }
    370 }
    371 #endif  // VERIFY_HEAP
    372 
    373 
    374 static void ClearMarkbitsInPagedSpace(PagedSpace* space) {
    375   for (Page* p : *space) {
    376     p->ClearLiveness();
    377   }
    378 }
    379 
    380 
    381 static void ClearMarkbitsInNewSpace(NewSpace* space) {
    382   for (Page* page : *space) {
    383     page->ClearLiveness();
    384   }
    385 }
    386 
    387 
    388 void MarkCompactCollector::ClearMarkbits() {
    389   ClearMarkbitsInPagedSpace(heap_->code_space());
    390   ClearMarkbitsInPagedSpace(heap_->map_space());
    391   ClearMarkbitsInPagedSpace(heap_->old_space());
    392   ClearMarkbitsInNewSpace(heap_->new_space());
    393 
    394   LargeObjectIterator it(heap_->lo_space());
    395   for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
    396     ObjectMarking::ClearMarkBit(obj);
    397     MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
    398     chunk->ResetProgressBar();
    399     chunk->ResetLiveBytes();
    400   }
    401 }
    402 
    403 class MarkCompactCollector::Sweeper::SweeperTask : public v8::Task {
    404  public:
    405   SweeperTask(Sweeper* sweeper, base::Semaphore* pending_sweeper_tasks,
    406               AllocationSpace space_to_start)
    407       : sweeper_(sweeper),
    408         pending_sweeper_tasks_(pending_sweeper_tasks),
    409         space_to_start_(space_to_start) {}
    410 
    411   virtual ~SweeperTask() {}
    412 
    413  private:
    414   // v8::Task overrides.
    415   void Run() override {
    416     DCHECK_GE(space_to_start_, FIRST_SPACE);
    417     DCHECK_LE(space_to_start_, LAST_PAGED_SPACE);
    418     const int offset = space_to_start_ - FIRST_SPACE;
    419     const int num_spaces = LAST_PAGED_SPACE - FIRST_SPACE + 1;
    420     for (int i = 0; i < num_spaces; i++) {
    421       const int space_id = FIRST_SPACE + ((i + offset) % num_spaces);
    422       DCHECK_GE(space_id, FIRST_SPACE);
    423       DCHECK_LE(space_id, LAST_PAGED_SPACE);
    424       sweeper_->ParallelSweepSpace(static_cast<AllocationSpace>(space_id), 0);
    425     }
    426     pending_sweeper_tasks_->Signal();
    427   }
    428 
    429   Sweeper* sweeper_;
    430   base::Semaphore* pending_sweeper_tasks_;
    431   AllocationSpace space_to_start_;
    432 
    433   DISALLOW_COPY_AND_ASSIGN(SweeperTask);
    434 };
    435 
    436 void MarkCompactCollector::Sweeper::StartSweeping() {
    437   sweeping_in_progress_ = true;
    438   ForAllSweepingSpaces([this](AllocationSpace space) {
    439     std::sort(sweeping_list_[space].begin(), sweeping_list_[space].end(),
    440               [](Page* a, Page* b) { return a->LiveBytes() < b->LiveBytes(); });
    441   });
    442 }
    443 
    444 void MarkCompactCollector::Sweeper::StartSweeperTasks() {
    445   if (FLAG_concurrent_sweeping && sweeping_in_progress_) {
    446     ForAllSweepingSpaces([this](AllocationSpace space) {
    447       if (space == NEW_SPACE) return;
    448       num_sweeping_tasks_.Increment(1);
    449       V8::GetCurrentPlatform()->CallOnBackgroundThread(
    450           new SweeperTask(this, &pending_sweeper_tasks_semaphore_, space),
    451           v8::Platform::kShortRunningTask);
    452     });
    453   }
    454 }
    455 
    456 void MarkCompactCollector::Sweeper::SweepOrWaitUntilSweepingCompleted(
    457     Page* page) {
    458   if (!page->SweepingDone()) {
    459     ParallelSweepPage(page, page->owner()->identity());
    460     if (!page->SweepingDone()) {
    461       // We were not able to sweep that page, i.e., a concurrent
    462       // sweeper thread currently owns this page. Wait for the sweeper
    463       // thread to be done with this page.
    464       page->WaitUntilSweepingCompleted();
    465     }
    466   }
    467 }
    468 
    469 void MarkCompactCollector::SweepAndRefill(CompactionSpace* space) {
    470   if (FLAG_concurrent_sweeping &&
    471       !sweeper().IsSweepingCompleted(space->identity())) {
    472     sweeper().ParallelSweepSpace(space->identity(), 0);
    473     space->RefillFreeList();
    474   }
    475 }
    476 
    477 Page* MarkCompactCollector::Sweeper::GetSweptPageSafe(PagedSpace* space) {
    478   base::LockGuard<base::Mutex> guard(&mutex_);
    479   SweptList& list = swept_list_[space->identity()];
    480   if (list.length() > 0) {
    481     return list.RemoveLast();
    482   }
    483   return nullptr;
    484 }
    485 
    486 void MarkCompactCollector::Sweeper::EnsureCompleted() {
    487   if (!sweeping_in_progress_) return;
    488 
    489   // If sweeping is not completed or not running at all, we try to complete it
    490   // here.
    491   ForAllSweepingSpaces([this](AllocationSpace space) {
    492     if (!FLAG_concurrent_sweeping || !this->IsSweepingCompleted(space)) {
    493       ParallelSweepSpace(space, 0);
    494     }
    495   });
    496 
    497   if (FLAG_concurrent_sweeping) {
    498     while (num_sweeping_tasks_.Value() > 0) {
    499       pending_sweeper_tasks_semaphore_.Wait();
    500       num_sweeping_tasks_.Increment(-1);
    501     }
    502   }
    503 
    504   ForAllSweepingSpaces([this](AllocationSpace space) {
    505     if (space == NEW_SPACE) {
    506       swept_list_[NEW_SPACE].Clear();
    507     }
    508     DCHECK(sweeping_list_[space].empty());
    509   });
    510   sweeping_in_progress_ = false;
    511 }
    512 
    513 void MarkCompactCollector::Sweeper::EnsureNewSpaceCompleted() {
    514   if (!sweeping_in_progress_) return;
    515   if (!FLAG_concurrent_sweeping || !IsSweepingCompleted(NEW_SPACE)) {
    516     for (Page* p : *heap_->new_space()) {
    517       SweepOrWaitUntilSweepingCompleted(p);
    518     }
    519   }
    520 }
    521 
    522 void MarkCompactCollector::EnsureSweepingCompleted() {
    523   if (!sweeper().sweeping_in_progress()) return;
    524 
    525   sweeper().EnsureCompleted();
    526   heap()->old_space()->RefillFreeList();
    527   heap()->code_space()->RefillFreeList();
    528   heap()->map_space()->RefillFreeList();
    529 
    530 #ifdef VERIFY_HEAP
    531   if (FLAG_verify_heap && !evacuation()) {
    532     VerifyEvacuation(heap_);
    533   }
    534 #endif
    535 }
    536 
    537 bool MarkCompactCollector::Sweeper::AreSweeperTasksRunning() {
    538   DCHECK(FLAG_concurrent_sweeping);
    539   while (pending_sweeper_tasks_semaphore_.WaitFor(
    540       base::TimeDelta::FromSeconds(0))) {
    541     num_sweeping_tasks_.Increment(-1);
    542   }
    543   return num_sweeping_tasks_.Value() != 0;
    544 }
    545 
    546 bool MarkCompactCollector::Sweeper::IsSweepingCompleted(AllocationSpace space) {
    547   DCHECK(FLAG_concurrent_sweeping);
    548   if (AreSweeperTasksRunning()) return false;
    549   base::LockGuard<base::Mutex> guard(&mutex_);
    550   return sweeping_list_[space].empty();
    551 }
    552 
    553 const char* AllocationSpaceName(AllocationSpace space) {
    554   switch (space) {
    555     case NEW_SPACE:
    556       return "NEW_SPACE";
    557     case OLD_SPACE:
    558       return "OLD_SPACE";
    559     case CODE_SPACE:
    560       return "CODE_SPACE";
    561     case MAP_SPACE:
    562       return "MAP_SPACE";
    563     case LO_SPACE:
    564       return "LO_SPACE";
    565     default:
    566       UNREACHABLE();
    567   }
    568 
    569   return NULL;
    570 }
    571 
    572 void MarkCompactCollector::ComputeEvacuationHeuristics(
    573     size_t area_size, int* target_fragmentation_percent,
    574     size_t* max_evacuated_bytes) {
    575   // For memory reducing and optimize for memory mode we directly define both
    576   // constants.
    577   const int kTargetFragmentationPercentForReduceMemory = 20;
    578   const size_t kMaxEvacuatedBytesForReduceMemory = 12 * MB;
    579   const int kTargetFragmentationPercentForOptimizeMemory = 20;
    580   const size_t kMaxEvacuatedBytesForOptimizeMemory = 6 * MB;
    581 
    582   // For regular mode (which is latency critical) we define less aggressive
    583   // defaults to start and switch to a trace-based (using compaction speed)
    584   // approach as soon as we have enough samples.
    585   const int kTargetFragmentationPercent = 70;
    586   const size_t kMaxEvacuatedBytes = 4 * MB;
    587   // Time to take for a single area (=payload of page). Used as soon as there
    588   // exist enough compaction speed samples.
    589   const float kTargetMsPerArea = .5;
    590 
    591   if (heap()->ShouldReduceMemory()) {
    592     *target_fragmentation_percent = kTargetFragmentationPercentForReduceMemory;
    593     *max_evacuated_bytes = kMaxEvacuatedBytesForReduceMemory;
    594   } else if (heap()->ShouldOptimizeForMemoryUsage()) {
    595     *target_fragmentation_percent =
    596         kTargetFragmentationPercentForOptimizeMemory;
    597     *max_evacuated_bytes = kMaxEvacuatedBytesForOptimizeMemory;
    598   } else {
    599     const double estimated_compaction_speed =
    600         heap()->tracer()->CompactionSpeedInBytesPerMillisecond();
    601     if (estimated_compaction_speed != 0) {
    602       // Estimate the target fragmentation based on traced compaction speed
    603       // and a goal for a single page.
    604       const double estimated_ms_per_area =
    605           1 + area_size / estimated_compaction_speed;
    606       *target_fragmentation_percent = static_cast<int>(
    607           100 - 100 * kTargetMsPerArea / estimated_ms_per_area);
    608       if (*target_fragmentation_percent <
    609           kTargetFragmentationPercentForReduceMemory) {
    610         *target_fragmentation_percent =
    611             kTargetFragmentationPercentForReduceMemory;
    612       }
    613     } else {
    614       *target_fragmentation_percent = kTargetFragmentationPercent;
    615     }
    616     *max_evacuated_bytes = kMaxEvacuatedBytes;
    617   }
    618 }
    619 
    620 
    621 void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) {
    622   DCHECK(space->identity() == OLD_SPACE || space->identity() == CODE_SPACE);
    623 
    624   int number_of_pages = space->CountTotalPages();
    625   size_t area_size = space->AreaSize();
    626 
    627   // Pairs of (live_bytes_in_page, page).
    628   typedef std::pair<size_t, Page*> LiveBytesPagePair;
    629   std::vector<LiveBytesPagePair> pages;
    630   pages.reserve(number_of_pages);
    631 
    632   DCHECK(!sweeping_in_progress());
    633   DCHECK(!FLAG_concurrent_sweeping ||
    634          sweeper().IsSweepingCompleted(space->identity()));
    635   Page* owner_of_linear_allocation_area =
    636       space->top() == space->limit()
    637           ? nullptr
    638           : Page::FromAllocationAreaAddress(space->top());
    639   for (Page* p : *space) {
    640     if (p->NeverEvacuate() || p == owner_of_linear_allocation_area) continue;
    641     // Invariant: Evacuation candidates are just created when marking is
    642     // started. This means that sweeping has finished. Furthermore, at the end
    643     // of a GC all evacuation candidates are cleared and their slot buffers are
    644     // released.
    645     CHECK(!p->IsEvacuationCandidate());
    646     CHECK_NULL(p->old_to_old_slots());
    647     CHECK_NULL(p->typed_old_to_old_slots());
    648     CHECK(p->SweepingDone());
    649     DCHECK(p->area_size() == area_size);
    650     pages.push_back(std::make_pair(p->LiveBytesFromFreeList(), p));
    651   }
    652 
    653   int candidate_count = 0;
    654   size_t total_live_bytes = 0;
    655 
    656   const bool reduce_memory = heap()->ShouldReduceMemory();
    657   if (FLAG_manual_evacuation_candidates_selection) {
    658     for (size_t i = 0; i < pages.size(); i++) {
    659       Page* p = pages[i].second;
    660       if (p->IsFlagSet(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING)) {
    661         candidate_count++;
    662         total_live_bytes += pages[i].first;
    663         p->ClearFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING);
    664         AddEvacuationCandidate(p);
    665       }
    666     }
    667   } else if (FLAG_stress_compaction) {
    668     for (size_t i = 0; i < pages.size(); i++) {
    669       Page* p = pages[i].second;
    670       if (i % 2 == 0) {
    671         candidate_count++;
    672         total_live_bytes += pages[i].first;
    673         AddEvacuationCandidate(p);
    674       }
    675     }
    676   } else {
    677     // The following approach determines the pages that should be evacuated.
    678     //
    679     // We use two conditions to decide whether a page qualifies as an evacuation
    680     // candidate, or not:
    681     // * Target fragmentation: How fragmented is a page, i.e., how is the ratio
    682     //   between live bytes and capacity of this page (= area).
    683     // * Evacuation quota: A global quota determining how much bytes should be
    684     //   compacted.
    685     //
    686     // The algorithm sorts all pages by live bytes and then iterates through
    687     // them starting with the page with the most free memory, adding them to the
    688     // set of evacuation candidates as long as both conditions (fragmentation
    689     // and quota) hold.
    690     size_t max_evacuated_bytes;
    691     int target_fragmentation_percent;
    692     ComputeEvacuationHeuristics(area_size, &target_fragmentation_percent,
    693                                 &max_evacuated_bytes);
    694 
    695     const size_t free_bytes_threshold =
    696         target_fragmentation_percent * (area_size / 100);
    697 
    698     // Sort pages from the most free to the least free, then select
    699     // the first n pages for evacuation such that:
    700     // - the total size of evacuated objects does not exceed the specified
    701     // limit.
    702     // - fragmentation of (n+1)-th page does not exceed the specified limit.
    703     std::sort(pages.begin(), pages.end(),
    704               [](const LiveBytesPagePair& a, const LiveBytesPagePair& b) {
    705                 return a.first < b.first;
    706               });
    707     for (size_t i = 0; i < pages.size(); i++) {
    708       size_t live_bytes = pages[i].first;
    709       DCHECK_GE(area_size, live_bytes);
    710       size_t free_bytes = area_size - live_bytes;
    711       if (FLAG_always_compact ||
    712           ((free_bytes >= free_bytes_threshold) &&
    713            ((total_live_bytes + live_bytes) <= max_evacuated_bytes))) {
    714         candidate_count++;
    715         total_live_bytes += live_bytes;
    716       }
    717       if (FLAG_trace_fragmentation_verbose) {
    718         PrintIsolate(isolate(),
    719                      "compaction-selection-page: space=%s free_bytes_page=%zu "
    720                      "fragmentation_limit_kb=%" PRIuS
    721                      " fragmentation_limit_percent=%d sum_compaction_kb=%zu "
    722                      "compaction_limit_kb=%zu\n",
    723                      AllocationSpaceName(space->identity()), free_bytes / KB,
    724                      free_bytes_threshold / KB, target_fragmentation_percent,
    725                      total_live_bytes / KB, max_evacuated_bytes / KB);
    726       }
    727     }
    728     // How many pages we will allocated for the evacuated objects
    729     // in the worst case: ceil(total_live_bytes / area_size)
    730     int estimated_new_pages =
    731         static_cast<int>((total_live_bytes + area_size - 1) / area_size);
    732     DCHECK_LE(estimated_new_pages, candidate_count);
    733     int estimated_released_pages = candidate_count - estimated_new_pages;
    734     // Avoid (compact -> expand) cycles.
    735     if ((estimated_released_pages == 0) && !FLAG_always_compact) {
    736       candidate_count = 0;
    737     }
    738     for (int i = 0; i < candidate_count; i++) {
    739       AddEvacuationCandidate(pages[i].second);
    740     }
    741   }
    742 
    743   if (FLAG_trace_fragmentation) {
    744     PrintIsolate(isolate(),
    745                  "compaction-selection: space=%s reduce_memory=%d pages=%d "
    746                  "total_live_bytes=%zu\n",
    747                  AllocationSpaceName(space->identity()), reduce_memory,
    748                  candidate_count, total_live_bytes / KB);
    749   }
    750 }
    751 
    752 
    753 void MarkCompactCollector::AbortCompaction() {
    754   if (compacting_) {
    755     RememberedSet<OLD_TO_OLD>::ClearAll(heap());
    756     for (Page* p : evacuation_candidates_) {
    757       p->ClearEvacuationCandidate();
    758     }
    759     compacting_ = false;
    760     evacuation_candidates_.Rewind(0);
    761   }
    762   DCHECK_EQ(0, evacuation_candidates_.length());
    763 }
    764 
    765 
    766 void MarkCompactCollector::Prepare() {
    767   was_marked_incrementally_ = heap()->incremental_marking()->IsMarking();
    768 
    769 #ifdef DEBUG
    770   DCHECK(state_ == IDLE);
    771   state_ = PREPARE_GC;
    772 #endif
    773 
    774   DCHECK(!FLAG_never_compact || !FLAG_always_compact);
    775 
    776   // Instead of waiting we could also abort the sweeper threads here.
    777   EnsureSweepingCompleted();
    778 
    779   if (heap()->incremental_marking()->IsSweeping()) {
    780     heap()->incremental_marking()->Stop();
    781   }
    782 
    783   // If concurrent unmapping tasks are still running, we should wait for
    784   // them here.
    785   heap()->memory_allocator()->unmapper()->WaitUntilCompleted();
    786 
    787   // Clear marking bits if incremental marking is aborted.
    788   if (was_marked_incrementally_ && heap_->ShouldAbortIncrementalMarking()) {
    789     heap()->incremental_marking()->Stop();
    790     heap()->incremental_marking()->AbortBlackAllocation();
    791     ClearMarkbits();
    792     AbortWeakCollections();
    793     AbortWeakCells();
    794     AbortTransitionArrays();
    795     AbortCompaction();
    796     heap_->local_embedder_heap_tracer()->AbortTracing();
    797     marking_deque()->Clear();
    798     was_marked_incrementally_ = false;
    799   }
    800 
    801   if (!was_marked_incrementally_) {
    802     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_WRAPPER_PROLOGUE);
    803     heap_->local_embedder_heap_tracer()->TracePrologue();
    804   }
    805 
    806   // Don't start compaction if we are in the middle of incremental
    807   // marking cycle. We did not collect any slots.
    808   if (!FLAG_never_compact && !was_marked_incrementally_) {
    809     StartCompaction();
    810   }
    811 
    812   PagedSpaces spaces(heap());
    813   for (PagedSpace* space = spaces.next(); space != NULL;
    814        space = spaces.next()) {
    815     space->PrepareForMarkCompact();
    816   }
    817   heap()->account_external_memory_concurrently_freed();
    818 
    819 #ifdef VERIFY_HEAP
    820   if (!was_marked_incrementally_ && FLAG_verify_heap) {
    821     VerifyMarkbitsAreClean();
    822   }
    823 #endif
    824 }
    825 
    826 
    827 void MarkCompactCollector::Finish() {
    828   TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_FINISH);
    829 
    830   if (!heap()->delay_sweeper_tasks_for_testing_) {
    831     sweeper().StartSweeperTasks();
    832   }
    833 
    834   // The hashing of weak_object_to_code_table is no longer valid.
    835   heap()->weak_object_to_code_table()->Rehash(
    836       heap()->isolate()->factory()->undefined_value());
    837 
    838   // Clear the marking state of live large objects.
    839   heap_->lo_space()->ClearMarkingStateOfLiveObjects();
    840 
    841 #ifdef DEBUG
    842   DCHECK(state_ == SWEEP_SPACES || state_ == RELOCATE_OBJECTS);
    843   state_ = IDLE;
    844 #endif
    845   heap_->isolate()->inner_pointer_to_code_cache()->Flush();
    846 
    847   // The stub caches are not traversed during GC; clear them to force
    848   // their lazy re-initialization. This must be done after the
    849   // GC, because it relies on the new address of certain old space
    850   // objects (empty string, illegal builtin).
    851   isolate()->load_stub_cache()->Clear();
    852   isolate()->store_stub_cache()->Clear();
    853 
    854   if (have_code_to_deoptimize_) {
    855     // Some code objects were marked for deoptimization during the GC.
    856     Deoptimizer::DeoptimizeMarkedCode(isolate());
    857     have_code_to_deoptimize_ = false;
    858   }
    859 
    860   heap_->incremental_marking()->ClearIdleMarkingDelayCounter();
    861 }
    862 
    863 
    864 // -------------------------------------------------------------------------
    865 // Phase 1: tracing and marking live objects.
    866 //   before: all objects are in normal state.
    867 //   after: a live object's map pointer is marked as '00'.
    868 
    869 // Marking all live objects in the heap as part of mark-sweep or mark-compact
    870 // collection.  Before marking, all objects are in their normal state.  After
    871 // marking, live objects' map pointers are marked indicating that the object
    872 // has been found reachable.
    873 //
    874 // The marking algorithm is a (mostly) depth-first (because of possible stack
    875 // overflow) traversal of the graph of objects reachable from the roots.  It
    876 // uses an explicit stack of pointers rather than recursion.  The young
    877 // generation's inactive ('from') space is used as a marking stack.  The
    878 // objects in the marking stack are the ones that have been reached and marked
    879 // but their children have not yet been visited.
    880 //
    881 // The marking stack can overflow during traversal.  In that case, we set an
    882 // overflow flag.  When the overflow flag is set, we continue marking objects
    883 // reachable from the objects on the marking stack, but no longer push them on
    884 // the marking stack.  Instead, we mark them as both marked and overflowed.
    885 // When the stack is in the overflowed state, objects marked as overflowed
    886 // have been reached and marked but their children have not been visited yet.
    887 // After emptying the marking stack, we clear the overflow flag and traverse
    888 // the heap looking for objects marked as overflowed, push them on the stack,
    889 // and continue with marking.  This process repeats until all reachable
    890 // objects have been marked.
    891 
    892 void CodeFlusher::ProcessJSFunctionCandidates() {
    893   Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kCompileLazy);
    894   Code* interpreter_entry_trampoline =
    895       isolate_->builtins()->builtin(Builtins::kInterpreterEntryTrampoline);
    896   Object* undefined = isolate_->heap()->undefined_value();
    897 
    898   JSFunction* candidate = jsfunction_candidates_head_;
    899   JSFunction* next_candidate;
    900   while (candidate != NULL) {
    901     next_candidate = GetNextCandidate(candidate);
    902     ClearNextCandidate(candidate, undefined);
    903 
    904     SharedFunctionInfo* shared = candidate->shared();
    905 
    906     Code* code = shared->code();
    907     if (ObjectMarking::IsWhite(code)) {
    908       if (FLAG_trace_code_flushing && shared->is_compiled()) {
    909         PrintF("[code-flushing clears: ");
    910         shared->ShortPrint();
    911         PrintF(" - age: %d]\n", code->GetAge());
    912       }
    913       // Always flush the optimized code map if there is one.
    914       if (!shared->OptimizedCodeMapIsCleared()) {
    915         shared->ClearOptimizedCodeMap();
    916       }
    917       if (shared->HasBytecodeArray()) {
    918         shared->set_code(interpreter_entry_trampoline);
    919         candidate->set_code(interpreter_entry_trampoline);
    920       } else {
    921         shared->set_code(lazy_compile);
    922         candidate->set_code(lazy_compile);
    923       }
    924     } else {
    925       DCHECK(ObjectMarking::IsBlack(code));
    926       candidate->set_code(code);
    927     }
    928 
    929     // We are in the middle of a GC cycle so the write barrier in the code
    930     // setter did not record the slot update and we have to do that manually.
    931     Address slot = candidate->address() + JSFunction::kCodeEntryOffset;
    932     Code* target = Code::cast(Code::GetObjectFromEntryAddress(slot));
    933     isolate_->heap()->mark_compact_collector()->RecordCodeEntrySlot(
    934         candidate, slot, target);
    935 
    936     Object** shared_code_slot =
    937         HeapObject::RawField(shared, SharedFunctionInfo::kCodeOffset);
    938     isolate_->heap()->mark_compact_collector()->RecordSlot(
    939         shared, shared_code_slot, *shared_code_slot);
    940 
    941     candidate = next_candidate;
    942   }
    943 
    944   jsfunction_candidates_head_ = NULL;
    945 }
    946 
    947 
    948 void CodeFlusher::ProcessSharedFunctionInfoCandidates() {
    949   Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kCompileLazy);
    950   Code* interpreter_entry_trampoline =
    951       isolate_->builtins()->builtin(Builtins::kInterpreterEntryTrampoline);
    952   SharedFunctionInfo* candidate = shared_function_info_candidates_head_;
    953   SharedFunctionInfo* next_candidate;
    954   while (candidate != NULL) {
    955     next_candidate = GetNextCandidate(candidate);
    956     ClearNextCandidate(candidate);
    957 
    958     Code* code = candidate->code();
    959     if (ObjectMarking::IsWhite(code)) {
    960       if (FLAG_trace_code_flushing && candidate->is_compiled()) {
    961         PrintF("[code-flushing clears: ");
    962         candidate->ShortPrint();
    963         PrintF(" - age: %d]\n", code->GetAge());
    964       }
    965       // Always flush the optimized code map if there is one.
    966       if (!candidate->OptimizedCodeMapIsCleared()) {
    967         candidate->ClearOptimizedCodeMap();
    968       }
    969       if (candidate->HasBytecodeArray()) {
    970         candidate->set_code(interpreter_entry_trampoline);
    971       } else {
    972         candidate->set_code(lazy_compile);
    973       }
    974     }
    975 
    976     Object** code_slot =
    977         HeapObject::RawField(candidate, SharedFunctionInfo::kCodeOffset);
    978     isolate_->heap()->mark_compact_collector()->RecordSlot(candidate, code_slot,
    979                                                            *code_slot);
    980 
    981     candidate = next_candidate;
    982   }
    983 
    984   shared_function_info_candidates_head_ = NULL;
    985 }
    986 
    987 
    988 void CodeFlusher::EvictCandidate(SharedFunctionInfo* shared_info) {
    989   // Make sure previous flushing decisions are revisited.
    990   isolate_->heap()->incremental_marking()->IterateBlackObject(shared_info);
    991 
    992   if (FLAG_trace_code_flushing) {
    993     PrintF("[code-flushing abandons function-info: ");
    994     shared_info->ShortPrint();
    995     PrintF("]\n");
    996   }
    997 
    998   SharedFunctionInfo* candidate = shared_function_info_candidates_head_;
    999   SharedFunctionInfo* next_candidate;
   1000   if (candidate == shared_info) {
   1001     next_candidate = GetNextCandidate(shared_info);
   1002     shared_function_info_candidates_head_ = next_candidate;
   1003     ClearNextCandidate(shared_info);
   1004   } else {
   1005     while (candidate != NULL) {
   1006       next_candidate = GetNextCandidate(candidate);
   1007 
   1008       if (next_candidate == shared_info) {
   1009         next_candidate = GetNextCandidate(shared_info);
   1010         SetNextCandidate(candidate, next_candidate);
   1011         ClearNextCandidate(shared_info);
   1012         break;
   1013       }
   1014 
   1015       candidate = next_candidate;
   1016     }
   1017   }
   1018 }
   1019 
   1020 
   1021 void CodeFlusher::EvictCandidate(JSFunction* function) {
   1022   DCHECK(!function->next_function_link()->IsUndefined(isolate_));
   1023   Object* undefined = isolate_->heap()->undefined_value();
   1024 
   1025   // Make sure previous flushing decisions are revisited.
   1026   isolate_->heap()->incremental_marking()->IterateBlackObject(function);
   1027   isolate_->heap()->incremental_marking()->IterateBlackObject(
   1028       function->shared());
   1029 
   1030   if (FLAG_trace_code_flushing) {
   1031     PrintF("[code-flushing abandons closure: ");
   1032     function->shared()->ShortPrint();
   1033     PrintF("]\n");
   1034   }
   1035 
   1036   JSFunction* candidate = jsfunction_candidates_head_;
   1037   JSFunction* next_candidate;
   1038   if (candidate == function) {
   1039     next_candidate = GetNextCandidate(function);
   1040     jsfunction_candidates_head_ = next_candidate;
   1041     ClearNextCandidate(function, undefined);
   1042   } else {
   1043     while (candidate != NULL) {
   1044       next_candidate = GetNextCandidate(candidate);
   1045 
   1046       if (next_candidate == function) {
   1047         next_candidate = GetNextCandidate(function);
   1048         SetNextCandidate(candidate, next_candidate);
   1049         ClearNextCandidate(function, undefined);
   1050         break;
   1051       }
   1052 
   1053       candidate = next_candidate;
   1054     }
   1055   }
   1056 }
   1057 
   1058 
   1059 void CodeFlusher::IteratePointersToFromSpace(ObjectVisitor* v) {
   1060   Heap* heap = isolate_->heap();
   1061 
   1062   JSFunction** slot = &jsfunction_candidates_head_;
   1063   JSFunction* candidate = jsfunction_candidates_head_;
   1064   while (candidate != NULL) {
   1065     if (heap->InFromSpace(candidate)) {
   1066       v->VisitPointer(reinterpret_cast<Object**>(slot));
   1067     }
   1068     candidate = GetNextCandidate(*slot);
   1069     slot = GetNextCandidateSlot(*slot);
   1070   }
   1071 }
   1072 
   1073 class StaticYoungGenerationMarkingVisitor
   1074     : public StaticNewSpaceVisitor<StaticYoungGenerationMarkingVisitor> {
   1075  public:
   1076   static void Initialize(Heap* heap) {
   1077     StaticNewSpaceVisitor<StaticYoungGenerationMarkingVisitor>::Initialize();
   1078   }
   1079 
   1080   inline static void VisitPointer(Heap* heap, HeapObject* object, Object** p) {
   1081     Object* target = *p;
   1082     if (heap->InNewSpace(target)) {
   1083       if (MarkRecursively(heap, HeapObject::cast(target))) return;
   1084       heap->mark_compact_collector()->MarkObject(HeapObject::cast(target));
   1085     }
   1086   }
   1087 
   1088  protected:
   1089   inline static bool MarkRecursively(Heap* heap, HeapObject* object) {
   1090     StackLimitCheck check(heap->isolate());
   1091     if (check.HasOverflowed()) return false;
   1092 
   1093     if (ObjectMarking::IsBlackOrGrey(object)) return true;
   1094     ObjectMarking::WhiteToBlack(object);
   1095     IterateBody(object->map(), object);
   1096     return true;
   1097   }
   1098 };
   1099 
   1100 class MarkCompactMarkingVisitor
   1101     : public StaticMarkingVisitor<MarkCompactMarkingVisitor> {
   1102  public:
   1103   static void Initialize();
   1104 
   1105   INLINE(static void VisitPointer(Heap* heap, HeapObject* object, Object** p)) {
   1106     MarkObjectByPointer(heap->mark_compact_collector(), object, p);
   1107   }
   1108 
   1109   INLINE(static void VisitPointers(Heap* heap, HeapObject* object,
   1110                                    Object** start, Object** end)) {
   1111     // Mark all objects pointed to in [start, end).
   1112     const int kMinRangeForMarkingRecursion = 64;
   1113     if (end - start >= kMinRangeForMarkingRecursion) {
   1114       if (VisitUnmarkedObjects(heap, object, start, end)) return;
   1115       // We are close to a stack overflow, so just mark the objects.
   1116     }
   1117     MarkCompactCollector* collector = heap->mark_compact_collector();
   1118     for (Object** p = start; p < end; p++) {
   1119       MarkObjectByPointer(collector, object, p);
   1120     }
   1121   }
   1122 
   1123   // Marks the object black and pushes it on the marking stack.
   1124   INLINE(static void MarkObject(Heap* heap, HeapObject* object)) {
   1125     heap->mark_compact_collector()->MarkObject(object);
   1126   }
   1127 
   1128   // Marks the object black without pushing it on the marking stack.
   1129   // Returns true if object needed marking and false otherwise.
   1130   INLINE(static bool MarkObjectWithoutPush(Heap* heap, HeapObject* object)) {
   1131     if (ObjectMarking::IsWhite(object)) {
   1132       ObjectMarking::WhiteToBlack(object);
   1133       return true;
   1134     }
   1135     return false;
   1136   }
   1137 
   1138   // Mark object pointed to by p.
   1139   INLINE(static void MarkObjectByPointer(MarkCompactCollector* collector,
   1140                                          HeapObject* object, Object** p)) {
   1141     if (!(*p)->IsHeapObject()) return;
   1142     HeapObject* target_object = HeapObject::cast(*p);
   1143     collector->RecordSlot(object, p, target_object);
   1144     collector->MarkObject(target_object);
   1145   }
   1146 
   1147 
   1148   // Visit an unmarked object.
   1149   INLINE(static void VisitUnmarkedObject(MarkCompactCollector* collector,
   1150                                          HeapObject* obj)) {
   1151 #ifdef DEBUG
   1152     DCHECK(collector->heap()->Contains(obj));
   1153     DCHECK(ObjectMarking::IsWhite(obj));
   1154 #endif
   1155     Map* map = obj->map();
   1156     Heap* heap = obj->GetHeap();
   1157     ObjectMarking::WhiteToBlack(obj);
   1158     // Mark the map pointer and the body.
   1159     heap->mark_compact_collector()->MarkObject(map);
   1160     IterateBody(map, obj);
   1161   }
   1162 
   1163   // Visit all unmarked objects pointed to by [start, end).
   1164   // Returns false if the operation fails (lack of stack space).
   1165   INLINE(static bool VisitUnmarkedObjects(Heap* heap, HeapObject* object,
   1166                                           Object** start, Object** end)) {
   1167     // Return false is we are close to the stack limit.
   1168     StackLimitCheck check(heap->isolate());
   1169     if (check.HasOverflowed()) return false;
   1170 
   1171     MarkCompactCollector* collector = heap->mark_compact_collector();
   1172     // Visit the unmarked objects.
   1173     for (Object** p = start; p < end; p++) {
   1174       Object* o = *p;
   1175       if (!o->IsHeapObject()) continue;
   1176       collector->RecordSlot(object, p, o);
   1177       HeapObject* obj = HeapObject::cast(o);
   1178       if (ObjectMarking::IsBlackOrGrey(obj)) continue;
   1179       VisitUnmarkedObject(collector, obj);
   1180     }
   1181     return true;
   1182   }
   1183 
   1184  private:
   1185   // Code flushing support.
   1186 
   1187   static const int kRegExpCodeThreshold = 5;
   1188 
   1189   static void UpdateRegExpCodeAgeAndFlush(Heap* heap, JSRegExp* re,
   1190                                           bool is_one_byte) {
   1191     // Make sure that the fixed array is in fact initialized on the RegExp.
   1192     // We could potentially trigger a GC when initializing the RegExp.
   1193     if (HeapObject::cast(re->data())->map()->instance_type() !=
   1194         FIXED_ARRAY_TYPE)
   1195       return;
   1196 
   1197     // Make sure this is a RegExp that actually contains code.
   1198     if (re->TypeTag() != JSRegExp::IRREGEXP) return;
   1199 
   1200     Object* code = re->DataAt(JSRegExp::code_index(is_one_byte));
   1201     if (!code->IsSmi() &&
   1202         HeapObject::cast(code)->map()->instance_type() == CODE_TYPE) {
   1203       // Save a copy that can be reinstated if we need the code again.
   1204       re->SetDataAt(JSRegExp::saved_code_index(is_one_byte), code);
   1205 
   1206       // Saving a copy might create a pointer into compaction candidate
   1207       // that was not observed by marker.  This might happen if JSRegExp data
   1208       // was marked through the compilation cache before marker reached JSRegExp
   1209       // object.
   1210       FixedArray* data = FixedArray::cast(re->data());
   1211       if (ObjectMarking::IsBlackOrGrey(data)) {
   1212         Object** slot =
   1213             data->data_start() + JSRegExp::saved_code_index(is_one_byte);
   1214         heap->mark_compact_collector()->RecordSlot(data, slot, code);
   1215       }
   1216 
   1217       // Set a number in the 0-255 range to guarantee no smi overflow.
   1218       re->SetDataAt(JSRegExp::code_index(is_one_byte),
   1219                     Smi::FromInt(heap->ms_count() & 0xff));
   1220     } else if (code->IsSmi()) {
   1221       int value = Smi::cast(code)->value();
   1222       // The regexp has not been compiled yet or there was a compilation error.
   1223       if (value == JSRegExp::kUninitializedValue ||
   1224           value == JSRegExp::kCompilationErrorValue) {
   1225         return;
   1226       }
   1227 
   1228       // Check if we should flush now.
   1229       if (value == ((heap->ms_count() - kRegExpCodeThreshold) & 0xff)) {
   1230         re->SetDataAt(JSRegExp::code_index(is_one_byte),
   1231                       Smi::FromInt(JSRegExp::kUninitializedValue));
   1232         re->SetDataAt(JSRegExp::saved_code_index(is_one_byte),
   1233                       Smi::FromInt(JSRegExp::kUninitializedValue));
   1234       }
   1235     }
   1236   }
   1237 
   1238 
   1239   // Works by setting the current sweep_generation (as a smi) in the
   1240   // code object place in the data array of the RegExp and keeps a copy
   1241   // around that can be reinstated if we reuse the RegExp before flushing.
   1242   // If we did not use the code for kRegExpCodeThreshold mark sweep GCs
   1243   // we flush the code.
   1244   static void VisitRegExpAndFlushCode(Map* map, HeapObject* object) {
   1245     Heap* heap = map->GetHeap();
   1246     MarkCompactCollector* collector = heap->mark_compact_collector();
   1247     if (!collector->is_code_flushing_enabled()) {
   1248       JSObjectVisitor::Visit(map, object);
   1249       return;
   1250     }
   1251     JSRegExp* re = reinterpret_cast<JSRegExp*>(object);
   1252     // Flush code or set age on both one byte and two byte code.
   1253     UpdateRegExpCodeAgeAndFlush(heap, re, true);
   1254     UpdateRegExpCodeAgeAndFlush(heap, re, false);
   1255     // Visit the fields of the RegExp, including the updated FixedArray.
   1256     JSObjectVisitor::Visit(map, object);
   1257   }
   1258 };
   1259 
   1260 
   1261 void MarkCompactMarkingVisitor::Initialize() {
   1262   StaticMarkingVisitor<MarkCompactMarkingVisitor>::Initialize();
   1263 
   1264   table_.Register(kVisitJSRegExp, &VisitRegExpAndFlushCode);
   1265 }
   1266 
   1267 
   1268 class CodeMarkingVisitor : public ThreadVisitor {
   1269  public:
   1270   explicit CodeMarkingVisitor(MarkCompactCollector* collector)
   1271       : collector_(collector) {}
   1272 
   1273   void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
   1274     collector_->PrepareThreadForCodeFlushing(isolate, top);
   1275   }
   1276 
   1277  private:
   1278   MarkCompactCollector* collector_;
   1279 };
   1280 
   1281 
   1282 class SharedFunctionInfoMarkingVisitor : public ObjectVisitor {
   1283  public:
   1284   explicit SharedFunctionInfoMarkingVisitor(MarkCompactCollector* collector)
   1285       : collector_(collector) {}
   1286 
   1287   void VisitPointers(Object** start, Object** end) override {
   1288     for (Object** p = start; p < end; p++) VisitPointer(p);
   1289   }
   1290 
   1291   void VisitPointer(Object** slot) override {
   1292     Object* obj = *slot;
   1293     if (obj->IsSharedFunctionInfo()) {
   1294       SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(obj);
   1295       collector_->MarkObject(shared->code());
   1296       collector_->MarkObject(shared);
   1297     }
   1298   }
   1299 
   1300  private:
   1301   MarkCompactCollector* collector_;
   1302 };
   1303 
   1304 
   1305 void MarkCompactCollector::PrepareThreadForCodeFlushing(Isolate* isolate,
   1306                                                         ThreadLocalTop* top) {
   1307   for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
   1308     // Note: for the frame that has a pending lazy deoptimization
   1309     // StackFrame::unchecked_code will return a non-optimized code object for
   1310     // the outermost function and StackFrame::LookupCode will return
   1311     // actual optimized code object.
   1312     StackFrame* frame = it.frame();
   1313     Code* code = frame->unchecked_code();
   1314     MarkObject(code);
   1315     if (frame->is_optimized()) {
   1316       Code* optimized_code = frame->LookupCode();
   1317       MarkObject(optimized_code);
   1318     }
   1319   }
   1320 }
   1321 
   1322 
   1323 void MarkCompactCollector::PrepareForCodeFlushing() {
   1324   // If code flushing is disabled, there is no need to prepare for it.
   1325   if (!is_code_flushing_enabled()) return;
   1326 
   1327   // Make sure we are not referencing the code from the stack.
   1328   DCHECK(this == heap()->mark_compact_collector());
   1329   PrepareThreadForCodeFlushing(heap()->isolate(),
   1330                                heap()->isolate()->thread_local_top());
   1331 
   1332   // Iterate the archived stacks in all threads to check if
   1333   // the code is referenced.
   1334   CodeMarkingVisitor code_marking_visitor(this);
   1335   heap()->isolate()->thread_manager()->IterateArchivedThreads(
   1336       &code_marking_visitor);
   1337 
   1338   SharedFunctionInfoMarkingVisitor visitor(this);
   1339   heap()->isolate()->compilation_cache()->IterateFunctions(&visitor);
   1340   heap()->isolate()->handle_scope_implementer()->Iterate(&visitor);
   1341 
   1342   ProcessMarkingDeque<MarkCompactMode::FULL>();
   1343 }
   1344 
   1345 
   1346 // Visitor class for marking heap roots.
   1347 template <MarkCompactMode mode>
   1348 class RootMarkingVisitor : public ObjectVisitor {
   1349  public:
   1350   explicit RootMarkingVisitor(Heap* heap)
   1351       : collector_(heap->mark_compact_collector()) {}
   1352 
   1353   void VisitPointer(Object** p) override { MarkObjectByPointer(p); }
   1354 
   1355   void VisitPointers(Object** start, Object** end) override {
   1356     for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
   1357   }
   1358 
   1359   // Skip the weak next code link in a code object, which is visited in
   1360   // ProcessTopOptimizedFrame.
   1361   void VisitNextCodeLink(Object** p) override {}
   1362 
   1363  private:
   1364   void MarkObjectByPointer(Object** p) {
   1365     if (!(*p)->IsHeapObject()) return;
   1366 
   1367     HeapObject* object = HeapObject::cast(*p);
   1368 
   1369     if (mode == MarkCompactMode::YOUNG_GENERATION &&
   1370         !collector_->heap()->InNewSpace(object))
   1371       return;
   1372 
   1373     if (ObjectMarking::IsBlackOrGrey(object)) return;
   1374 
   1375     Map* map = object->map();
   1376     // Mark the object.
   1377     ObjectMarking::WhiteToBlack(object);
   1378 
   1379     switch (mode) {
   1380       case MarkCompactMode::FULL: {
   1381         // Mark the map pointer and body, and push them on the marking stack.
   1382         collector_->MarkObject(map);
   1383         MarkCompactMarkingVisitor::IterateBody(map, object);
   1384       } break;
   1385       case MarkCompactMode::YOUNG_GENERATION:
   1386         StaticYoungGenerationMarkingVisitor::IterateBody(map, object);
   1387         break;
   1388     }
   1389 
   1390     // Mark all the objects reachable from the map and body.  May leave
   1391     // overflowed objects in the heap.
   1392     collector_->EmptyMarkingDeque<mode>();
   1393   }
   1394 
   1395   MarkCompactCollector* collector_;
   1396 };
   1397 
   1398 
   1399 // Helper class for pruning the string table.
   1400 template <bool finalize_external_strings, bool record_slots>
   1401 class StringTableCleaner : public ObjectVisitor {
   1402  public:
   1403   StringTableCleaner(Heap* heap, HeapObject* table)
   1404       : heap_(heap), pointers_removed_(0), table_(table) {
   1405     DCHECK(!record_slots || table != nullptr);
   1406   }
   1407 
   1408   void VisitPointers(Object** start, Object** end) override {
   1409     // Visit all HeapObject pointers in [start, end).
   1410     MarkCompactCollector* collector = heap_->mark_compact_collector();
   1411     for (Object** p = start; p < end; p++) {
   1412       Object* o = *p;
   1413       if (o->IsHeapObject()) {
   1414         if (ObjectMarking::IsWhite(HeapObject::cast(o))) {
   1415           if (finalize_external_strings) {
   1416             if (o->IsExternalString()) {
   1417               heap_->FinalizeExternalString(String::cast(*p));
   1418             } else {
   1419               // The original external string may have been internalized.
   1420               DCHECK(o->IsThinString());
   1421             }
   1422           } else {
   1423             pointers_removed_++;
   1424           }
   1425           // Set the entry to the_hole_value (as deleted).
   1426           *p = heap_->the_hole_value();
   1427         } else if (record_slots) {
   1428           // StringTable contains only old space strings.
   1429           DCHECK(!heap_->InNewSpace(o));
   1430           collector->RecordSlot(table_, p, o);
   1431         }
   1432       }
   1433     }
   1434   }
   1435 
   1436   int PointersRemoved() {
   1437     DCHECK(!finalize_external_strings);
   1438     return pointers_removed_;
   1439   }
   1440 
   1441  private:
   1442   Heap* heap_;
   1443   int pointers_removed_;
   1444   HeapObject* table_;
   1445 };
   1446 
   1447 typedef StringTableCleaner<false, true> InternalizedStringTableCleaner;
   1448 typedef StringTableCleaner<true, false> ExternalStringTableCleaner;
   1449 
   1450 // Implementation of WeakObjectRetainer for mark compact GCs. All marked objects
   1451 // are retained.
   1452 class MarkCompactWeakObjectRetainer : public WeakObjectRetainer {
   1453  public:
   1454   virtual Object* RetainAs(Object* object) {
   1455     DCHECK(!ObjectMarking::IsGrey(HeapObject::cast(object)));
   1456     if (ObjectMarking::IsBlack(HeapObject::cast(object))) {
   1457       return object;
   1458     } else if (object->IsAllocationSite() &&
   1459                !(AllocationSite::cast(object)->IsZombie())) {
   1460       // "dead" AllocationSites need to live long enough for a traversal of new
   1461       // space. These sites get a one-time reprieve.
   1462       AllocationSite* site = AllocationSite::cast(object);
   1463       site->MarkZombie();
   1464       ObjectMarking::WhiteToBlack(site);
   1465       return object;
   1466     } else {
   1467       return NULL;
   1468     }
   1469   }
   1470 };
   1471 
   1472 
   1473 // Fill the marking stack with overflowed objects returned by the given
   1474 // iterator.  Stop when the marking stack is filled or the end of the space
   1475 // is reached, whichever comes first.
   1476 template <class T>
   1477 void MarkCompactCollector::DiscoverGreyObjectsWithIterator(T* it) {
   1478   // The caller should ensure that the marking stack is initially not full,
   1479   // so that we don't waste effort pointlessly scanning for objects.
   1480   DCHECK(!marking_deque()->IsFull());
   1481 
   1482   Map* filler_map = heap()->one_pointer_filler_map();
   1483   for (HeapObject* object = it->Next(); object != NULL; object = it->Next()) {
   1484     if ((object->map() != filler_map) && ObjectMarking::IsGrey(object)) {
   1485       ObjectMarking::GreyToBlack(object);
   1486       PushBlack(object);
   1487       if (marking_deque()->IsFull()) return;
   1488     }
   1489   }
   1490 }
   1491 
   1492 void MarkCompactCollector::DiscoverGreyObjectsOnPage(MemoryChunk* p) {
   1493   DCHECK(!marking_deque()->IsFull());
   1494   LiveObjectIterator<kGreyObjects> it(p);
   1495   HeapObject* object = NULL;
   1496   while ((object = it.Next()) != NULL) {
   1497     DCHECK(ObjectMarking::IsGrey(object));
   1498     ObjectMarking::GreyToBlack(object);
   1499     PushBlack(object);
   1500     if (marking_deque()->IsFull()) return;
   1501   }
   1502 }
   1503 
   1504 class RecordMigratedSlotVisitor final : public ObjectVisitor {
   1505  public:
   1506   explicit RecordMigratedSlotVisitor(MarkCompactCollector* collector)
   1507       : collector_(collector) {}
   1508 
   1509   inline void VisitPointer(Object** p) final {
   1510     RecordMigratedSlot(*p, reinterpret_cast<Address>(p));
   1511   }
   1512 
   1513   inline void VisitPointers(Object** start, Object** end) final {
   1514     while (start < end) {
   1515       RecordMigratedSlot(*start, reinterpret_cast<Address>(start));
   1516       ++start;
   1517     }
   1518   }
   1519 
   1520   inline void VisitCodeEntry(Address code_entry_slot) final {
   1521     Address code_entry = Memory::Address_at(code_entry_slot);
   1522     if (Page::FromAddress(code_entry)->IsEvacuationCandidate()) {
   1523       RememberedSet<OLD_TO_OLD>::InsertTyped(Page::FromAddress(code_entry_slot),
   1524                                              nullptr, CODE_ENTRY_SLOT,
   1525                                              code_entry_slot);
   1526     }
   1527   }
   1528 
   1529   inline void VisitCodeTarget(RelocInfo* rinfo) final {
   1530     DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
   1531     Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
   1532     Code* host = rinfo->host();
   1533     // The target is always in old space, we don't have to record the slot in
   1534     // the old-to-new remembered set.
   1535     DCHECK(!collector_->heap()->InNewSpace(target));
   1536     collector_->RecordRelocSlot(host, rinfo, target);
   1537   }
   1538 
   1539   inline void VisitDebugTarget(RelocInfo* rinfo) final {
   1540     DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
   1541            rinfo->IsPatchedDebugBreakSlotSequence());
   1542     Code* target = Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
   1543     Code* host = rinfo->host();
   1544     // The target is always in old space, we don't have to record the slot in
   1545     // the old-to-new remembered set.
   1546     DCHECK(!collector_->heap()->InNewSpace(target));
   1547     collector_->RecordRelocSlot(host, rinfo, target);
   1548   }
   1549 
   1550   inline void VisitEmbeddedPointer(RelocInfo* rinfo) final {
   1551     DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
   1552     HeapObject* object = HeapObject::cast(rinfo->target_object());
   1553     Code* host = rinfo->host();
   1554     collector_->heap()->RecordWriteIntoCode(host, rinfo, object);
   1555     collector_->RecordRelocSlot(host, rinfo, object);
   1556   }
   1557 
   1558   inline void VisitCell(RelocInfo* rinfo) final {
   1559     DCHECK(rinfo->rmode() == RelocInfo::CELL);
   1560     Cell* cell = rinfo->target_cell();
   1561     Code* host = rinfo->host();
   1562     // The cell is always in old space, we don't have to record the slot in
   1563     // the old-to-new remembered set.
   1564     DCHECK(!collector_->heap()->InNewSpace(cell));
   1565     collector_->RecordRelocSlot(host, rinfo, cell);
   1566   }
   1567 
   1568   // Entries that will never move.
   1569   inline void VisitCodeAgeSequence(RelocInfo* rinfo) final {
   1570     DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
   1571     Code* stub = rinfo->code_age_stub();
   1572     USE(stub);
   1573     DCHECK(!Page::FromAddress(stub->address())->IsEvacuationCandidate());
   1574   }
   1575 
   1576   // Entries that are skipped for recording.
   1577   inline void VisitExternalReference(RelocInfo* rinfo) final {}
   1578   inline void VisitExternalReference(Address* p) final {}
   1579   inline void VisitRuntimeEntry(RelocInfo* rinfo) final {}
   1580   inline void VisitExternalOneByteString(
   1581       v8::String::ExternalOneByteStringResource** resource) final {}
   1582   inline void VisitExternalTwoByteString(
   1583       v8::String::ExternalStringResource** resource) final {}
   1584   inline void VisitInternalReference(RelocInfo* rinfo) final {}
   1585   inline void VisitEmbedderReference(Object** p, uint16_t class_id) final {}
   1586 
   1587  private:
   1588   inline void RecordMigratedSlot(Object* value, Address slot) {
   1589     if (value->IsHeapObject()) {
   1590       Page* p = Page::FromAddress(reinterpret_cast<Address>(value));
   1591       if (p->InNewSpace()) {
   1592         RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot);
   1593       } else if (p->IsEvacuationCandidate()) {
   1594         RememberedSet<OLD_TO_OLD>::Insert(Page::FromAddress(slot), slot);
   1595       }
   1596     }
   1597   }
   1598 
   1599   MarkCompactCollector* collector_;
   1600 };
   1601 
   1602 class MarkCompactCollector::HeapObjectVisitor {
   1603  public:
   1604   virtual ~HeapObjectVisitor() {}
   1605   virtual bool Visit(HeapObject* object) = 0;
   1606 };
   1607 
   1608 class MarkCompactCollector::EvacuateVisitorBase
   1609     : public MarkCompactCollector::HeapObjectVisitor {
   1610  protected:
   1611   enum MigrationMode { kFast, kProfiled };
   1612 
   1613   EvacuateVisitorBase(Heap* heap, CompactionSpaceCollection* compaction_spaces)
   1614       : heap_(heap),
   1615         compaction_spaces_(compaction_spaces),
   1616         profiling_(
   1617             heap->isolate()->is_profiling() ||
   1618             heap->isolate()->logger()->is_logging_code_events() ||
   1619             heap->isolate()->heap_profiler()->is_tracking_object_moves()) {}
   1620 
   1621   inline bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object,
   1622                                 HeapObject** target_object) {
   1623 #ifdef VERIFY_HEAP
   1624     if (AbortCompactionForTesting(object)) return false;
   1625 #endif  // VERIFY_HEAP
   1626     int size = object->Size();
   1627     AllocationAlignment alignment = object->RequiredAlignment();
   1628     AllocationResult allocation = target_space->AllocateRaw(size, alignment);
   1629     if (allocation.To(target_object)) {
   1630       MigrateObject(*target_object, object, size, target_space->identity());
   1631       return true;
   1632     }
   1633     return false;
   1634   }
   1635 
   1636   inline void MigrateObject(HeapObject* dst, HeapObject* src, int size,
   1637                             AllocationSpace dest) {
   1638     if (profiling_) {
   1639       MigrateObject<kProfiled>(dst, src, size, dest);
   1640     } else {
   1641       MigrateObject<kFast>(dst, src, size, dest);
   1642     }
   1643   }
   1644 
   1645   template <MigrationMode mode>
   1646   inline void MigrateObject(HeapObject* dst, HeapObject* src, int size,
   1647                             AllocationSpace dest) {
   1648     Address dst_addr = dst->address();
   1649     Address src_addr = src->address();
   1650     DCHECK(heap_->AllowedToBeMigrated(src, dest));
   1651     DCHECK(dest != LO_SPACE);
   1652     if (dest == OLD_SPACE) {
   1653       DCHECK_OBJECT_SIZE(size);
   1654       DCHECK(IsAligned(size, kPointerSize));
   1655       heap_->CopyBlock(dst_addr, src_addr, size);
   1656       if ((mode == kProfiled) && dst->IsBytecodeArray()) {
   1657         PROFILE(heap_->isolate(),
   1658                 CodeMoveEvent(AbstractCode::cast(src), dst_addr));
   1659       }
   1660       RecordMigratedSlotVisitor visitor(heap_->mark_compact_collector());
   1661       dst->IterateBodyFast(dst->map()->instance_type(), size, &visitor);
   1662     } else if (dest == CODE_SPACE) {
   1663       DCHECK_CODEOBJECT_SIZE(size, heap_->code_space());
   1664       if (mode == kProfiled) {
   1665         PROFILE(heap_->isolate(),
   1666                 CodeMoveEvent(AbstractCode::cast(src), dst_addr));
   1667       }
   1668       heap_->CopyBlock(dst_addr, src_addr, size);
   1669       Code::cast(dst)->Relocate(dst_addr - src_addr);
   1670       RecordMigratedSlotVisitor visitor(heap_->mark_compact_collector());
   1671       dst->IterateBodyFast(dst->map()->instance_type(), size, &visitor);
   1672     } else {
   1673       DCHECK_OBJECT_SIZE(size);
   1674       DCHECK(dest == NEW_SPACE);
   1675       heap_->CopyBlock(dst_addr, src_addr, size);
   1676     }
   1677     if (mode == kProfiled) {
   1678       heap_->OnMoveEvent(dst, src, size);
   1679     }
   1680     Memory::Address_at(src_addr) = dst_addr;
   1681   }
   1682 
   1683 #ifdef VERIFY_HEAP
   1684   bool AbortCompactionForTesting(HeapObject* object) {
   1685     if (FLAG_stress_compaction) {
   1686       const uintptr_t mask = static_cast<uintptr_t>(FLAG_random_seed) &
   1687                              Page::kPageAlignmentMask & ~kPointerAlignmentMask;
   1688       if ((reinterpret_cast<uintptr_t>(object->address()) &
   1689            Page::kPageAlignmentMask) == mask) {
   1690         Page* page = Page::FromAddress(object->address());
   1691         if (page->IsFlagSet(Page::COMPACTION_WAS_ABORTED_FOR_TESTING)) {
   1692           page->ClearFlag(Page::COMPACTION_WAS_ABORTED_FOR_TESTING);
   1693         } else {
   1694           page->SetFlag(Page::COMPACTION_WAS_ABORTED_FOR_TESTING);
   1695           return true;
   1696         }
   1697       }
   1698     }
   1699     return false;
   1700   }
   1701 #endif  // VERIFY_HEAP
   1702 
   1703   Heap* heap_;
   1704   CompactionSpaceCollection* compaction_spaces_;
   1705   bool profiling_;
   1706 };
   1707 
   1708 class MarkCompactCollector::EvacuateNewSpaceVisitor final
   1709     : public MarkCompactCollector::EvacuateVisitorBase {
   1710  public:
   1711   static const intptr_t kLabSize = 4 * KB;
   1712   static const intptr_t kMaxLabObjectSize = 256;
   1713 
   1714   explicit EvacuateNewSpaceVisitor(Heap* heap,
   1715                                    CompactionSpaceCollection* compaction_spaces,
   1716                                    base::HashMap* local_pretenuring_feedback)
   1717       : EvacuateVisitorBase(heap, compaction_spaces),
   1718         buffer_(LocalAllocationBuffer::InvalidBuffer()),
   1719         space_to_allocate_(NEW_SPACE),
   1720         promoted_size_(0),
   1721         semispace_copied_size_(0),
   1722         local_pretenuring_feedback_(local_pretenuring_feedback) {}
   1723 
   1724   inline bool Visit(HeapObject* object) override {
   1725     heap_->UpdateAllocationSite<Heap::kCached>(object,
   1726                                                local_pretenuring_feedback_);
   1727     int size = object->Size();
   1728     HeapObject* target_object = nullptr;
   1729     if (heap_->ShouldBePromoted(object->address(), size) &&
   1730         TryEvacuateObject(compaction_spaces_->Get(OLD_SPACE), object,
   1731                           &target_object)) {
   1732       promoted_size_ += size;
   1733       return true;
   1734     }
   1735     HeapObject* target = nullptr;
   1736     AllocationSpace space = AllocateTargetObject(object, &target);
   1737     MigrateObject(HeapObject::cast(target), object, size, space);
   1738     semispace_copied_size_ += size;
   1739     return true;
   1740   }
   1741 
   1742   intptr_t promoted_size() { return promoted_size_; }
   1743   intptr_t semispace_copied_size() { return semispace_copied_size_; }
   1744 
   1745  private:
   1746   enum NewSpaceAllocationMode {
   1747     kNonstickyBailoutOldSpace,
   1748     kStickyBailoutOldSpace,
   1749   };
   1750 
   1751   inline AllocationSpace AllocateTargetObject(HeapObject* old_object,
   1752                                               HeapObject** target_object) {
   1753     const int size = old_object->Size();
   1754     AllocationAlignment alignment = old_object->RequiredAlignment();
   1755     AllocationResult allocation;
   1756     AllocationSpace space_allocated_in = space_to_allocate_;
   1757     if (space_to_allocate_ == NEW_SPACE) {
   1758       if (size > kMaxLabObjectSize) {
   1759         allocation =
   1760             AllocateInNewSpace(size, alignment, kNonstickyBailoutOldSpace);
   1761       } else {
   1762         allocation = AllocateInLab(size, alignment);
   1763       }
   1764     }
   1765     if (allocation.IsRetry() || (space_to_allocate_ == OLD_SPACE)) {
   1766       allocation = AllocateInOldSpace(size, alignment);
   1767       space_allocated_in = OLD_SPACE;
   1768     }
   1769     bool ok = allocation.To(target_object);
   1770     DCHECK(ok);
   1771     USE(ok);
   1772     return space_allocated_in;
   1773   }
   1774 
   1775   inline bool NewLocalAllocationBuffer() {
   1776     AllocationResult result =
   1777         AllocateInNewSpace(kLabSize, kWordAligned, kStickyBailoutOldSpace);
   1778     LocalAllocationBuffer saved_old_buffer = buffer_;
   1779     buffer_ = LocalAllocationBuffer::FromResult(heap_, result, kLabSize);
   1780     if (buffer_.IsValid()) {
   1781       buffer_.TryMerge(&saved_old_buffer);
   1782       return true;
   1783     }
   1784     return false;
   1785   }
   1786 
   1787   inline AllocationResult AllocateInNewSpace(int size_in_bytes,
   1788                                              AllocationAlignment alignment,
   1789                                              NewSpaceAllocationMode mode) {
   1790     AllocationResult allocation =
   1791         heap_->new_space()->AllocateRawSynchronized(size_in_bytes, alignment);
   1792     if (allocation.IsRetry()) {
   1793       if (!heap_->new_space()->AddFreshPageSynchronized()) {
   1794         if (mode == kStickyBailoutOldSpace) space_to_allocate_ = OLD_SPACE;
   1795       } else {
   1796         allocation = heap_->new_space()->AllocateRawSynchronized(size_in_bytes,
   1797                                                                  alignment);
   1798         if (allocation.IsRetry()) {
   1799           if (mode == kStickyBailoutOldSpace) space_to_allocate_ = OLD_SPACE;
   1800         }
   1801       }
   1802     }
   1803     return allocation;
   1804   }
   1805 
   1806   inline AllocationResult AllocateInOldSpace(int size_in_bytes,
   1807                                              AllocationAlignment alignment) {
   1808     AllocationResult allocation =
   1809         compaction_spaces_->Get(OLD_SPACE)->AllocateRaw(size_in_bytes,
   1810                                                         alignment);
   1811     if (allocation.IsRetry()) {
   1812       v8::internal::Heap::FatalProcessOutOfMemory(
   1813           "MarkCompactCollector: semi-space copy, fallback in old gen", true);
   1814     }
   1815     return allocation;
   1816   }
   1817 
   1818   inline AllocationResult AllocateInLab(int size_in_bytes,
   1819                                         AllocationAlignment alignment) {
   1820     AllocationResult allocation;
   1821     if (!buffer_.IsValid()) {
   1822       if (!NewLocalAllocationBuffer()) {
   1823         space_to_allocate_ = OLD_SPACE;
   1824         return AllocationResult::Retry(OLD_SPACE);
   1825       }
   1826     }
   1827     allocation = buffer_.AllocateRawAligned(size_in_bytes, alignment);
   1828     if (allocation.IsRetry()) {
   1829       if (!NewLocalAllocationBuffer()) {
   1830         space_to_allocate_ = OLD_SPACE;
   1831         return AllocationResult::Retry(OLD_SPACE);
   1832       } else {
   1833         allocation = buffer_.AllocateRawAligned(size_in_bytes, alignment);
   1834         if (allocation.IsRetry()) {
   1835           space_to_allocate_ = OLD_SPACE;
   1836           return AllocationResult::Retry(OLD_SPACE);
   1837         }
   1838       }
   1839     }
   1840     return allocation;
   1841   }
   1842 
   1843   LocalAllocationBuffer buffer_;
   1844   AllocationSpace space_to_allocate_;
   1845   intptr_t promoted_size_;
   1846   intptr_t semispace_copied_size_;
   1847   base::HashMap* local_pretenuring_feedback_;
   1848 };
   1849 
   1850 template <PageEvacuationMode mode>
   1851 class MarkCompactCollector::EvacuateNewSpacePageVisitor final
   1852     : public MarkCompactCollector::HeapObjectVisitor {
   1853  public:
   1854   explicit EvacuateNewSpacePageVisitor(
   1855       Heap* heap, base::HashMap* local_pretenuring_feedback)
   1856       : heap_(heap),
   1857         moved_bytes_(0),
   1858         local_pretenuring_feedback_(local_pretenuring_feedback) {}
   1859 
   1860   static void Move(Page* page) {
   1861     switch (mode) {
   1862       case NEW_TO_NEW:
   1863         page->heap()->new_space()->MovePageFromSpaceToSpace(page);
   1864         page->SetFlag(Page::PAGE_NEW_NEW_PROMOTION);
   1865         break;
   1866       case NEW_TO_OLD: {
   1867         page->Unlink();
   1868         Page* new_page = Page::ConvertNewToOld(page);
   1869         new_page->SetFlag(Page::PAGE_NEW_OLD_PROMOTION);
   1870         break;
   1871       }
   1872     }
   1873   }
   1874 
   1875   inline bool Visit(HeapObject* object) {
   1876     heap_->UpdateAllocationSite<Heap::kCached>(object,
   1877                                                local_pretenuring_feedback_);
   1878     if (mode == NEW_TO_OLD) {
   1879       RecordMigratedSlotVisitor visitor(heap_->mark_compact_collector());
   1880       object->IterateBodyFast(&visitor);
   1881     }
   1882     return true;
   1883   }
   1884 
   1885   intptr_t moved_bytes() { return moved_bytes_; }
   1886   void account_moved_bytes(intptr_t bytes) { moved_bytes_ += bytes; }
   1887 
   1888  private:
   1889   Heap* heap_;
   1890   intptr_t moved_bytes_;
   1891   base::HashMap* local_pretenuring_feedback_;
   1892 };
   1893 
   1894 class MarkCompactCollector::EvacuateOldSpaceVisitor final
   1895     : public MarkCompactCollector::EvacuateVisitorBase {
   1896  public:
   1897   EvacuateOldSpaceVisitor(Heap* heap,
   1898                           CompactionSpaceCollection* compaction_spaces)
   1899       : EvacuateVisitorBase(heap, compaction_spaces) {}
   1900 
   1901   inline bool Visit(HeapObject* object) override {
   1902     CompactionSpace* target_space = compaction_spaces_->Get(
   1903         Page::FromAddress(object->address())->owner()->identity());
   1904     HeapObject* target_object = nullptr;
   1905     if (TryEvacuateObject(target_space, object, &target_object)) {
   1906       DCHECK(object->map_word().IsForwardingAddress());
   1907       return true;
   1908     }
   1909     return false;
   1910   }
   1911 };
   1912 
   1913 class MarkCompactCollector::EvacuateRecordOnlyVisitor final
   1914     : public MarkCompactCollector::HeapObjectVisitor {
   1915  public:
   1916   explicit EvacuateRecordOnlyVisitor(Heap* heap) : heap_(heap) {}
   1917 
   1918   inline bool Visit(HeapObject* object) {
   1919     RecordMigratedSlotVisitor visitor(heap_->mark_compact_collector());
   1920     object->IterateBody(&visitor);
   1921     return true;
   1922   }
   1923 
   1924  private:
   1925   Heap* heap_;
   1926 };
   1927 
   1928 void MarkCompactCollector::DiscoverGreyObjectsInSpace(PagedSpace* space) {
   1929   for (Page* p : *space) {
   1930     DiscoverGreyObjectsOnPage(p);
   1931     if (marking_deque()->IsFull()) return;
   1932   }
   1933 }
   1934 
   1935 
   1936 void MarkCompactCollector::DiscoverGreyObjectsInNewSpace() {
   1937   NewSpace* space = heap()->new_space();
   1938   for (Page* page : PageRange(space->bottom(), space->top())) {
   1939     DiscoverGreyObjectsOnPage(page);
   1940     if (marking_deque()->IsFull()) return;
   1941   }
   1942 }
   1943 
   1944 
   1945 bool MarkCompactCollector::IsUnmarkedHeapObject(Object** p) {
   1946   Object* o = *p;
   1947   if (!o->IsHeapObject()) return false;
   1948   return ObjectMarking::IsWhite(HeapObject::cast(o));
   1949 }
   1950 
   1951 
   1952 bool MarkCompactCollector::IsUnmarkedHeapObjectWithHeap(Heap* heap,
   1953                                                         Object** p) {
   1954   Object* o = *p;
   1955   DCHECK(o->IsHeapObject());
   1956   return ObjectMarking::IsWhite(HeapObject::cast(o));
   1957 }
   1958 
   1959 void MarkCompactCollector::MarkStringTable(
   1960     RootMarkingVisitor<MarkCompactMode::FULL>* visitor) {
   1961   StringTable* string_table = heap()->string_table();
   1962   // Mark the string table itself.
   1963   if (ObjectMarking::IsWhite(string_table)) {
   1964     // String table could have already been marked by visiting the handles list.
   1965     ObjectMarking::WhiteToBlack(string_table);
   1966   }
   1967   // Explicitly mark the prefix.
   1968   string_table->IteratePrefix(visitor);
   1969   ProcessMarkingDeque<MarkCompactMode::FULL>();
   1970 }
   1971 
   1972 void MarkCompactCollector::MarkRoots(
   1973     RootMarkingVisitor<MarkCompactMode::FULL>* visitor) {
   1974   // Mark the heap roots including global variables, stack variables,
   1975   // etc., and all objects reachable from them.
   1976   heap()->IterateStrongRoots(visitor, VISIT_ONLY_STRONG);
   1977 
   1978   // Handle the string table specially.
   1979   MarkStringTable(visitor);
   1980 
   1981   // There may be overflowed objects in the heap.  Visit them now.
   1982   while (marking_deque()->overflowed()) {
   1983     RefillMarkingDeque<MarkCompactMode::FULL>();
   1984     EmptyMarkingDeque<MarkCompactMode::FULL>();
   1985   }
   1986 }
   1987 
   1988 
   1989 void MarkCompactCollector::MarkImplicitRefGroups(
   1990     MarkObjectFunction mark_object) {
   1991   List<ImplicitRefGroup*>* ref_groups =
   1992       isolate()->global_handles()->implicit_ref_groups();
   1993 
   1994   int last = 0;
   1995   for (int i = 0; i < ref_groups->length(); i++) {
   1996     ImplicitRefGroup* entry = ref_groups->at(i);
   1997     DCHECK(entry != NULL);
   1998 
   1999     if (ObjectMarking::IsWhite(*entry->parent)) {
   2000       (*ref_groups)[last++] = entry;
   2001       continue;
   2002     }
   2003 
   2004     Object*** children = entry->children;
   2005     // A parent object is marked, so mark all child heap objects.
   2006     for (size_t j = 0; j < entry->length; ++j) {
   2007       if ((*children[j])->IsHeapObject()) {
   2008         mark_object(heap(), HeapObject::cast(*children[j]));
   2009       }
   2010     }
   2011 
   2012     // Once the entire group has been marked, dispose it because it's
   2013     // not needed anymore.
   2014     delete entry;
   2015   }
   2016   ref_groups->Rewind(last);
   2017 }
   2018 
   2019 
   2020 // Mark all objects reachable from the objects on the marking stack.
   2021 // Before: the marking stack contains zero or more heap object pointers.
   2022 // After: the marking stack is empty, and all objects reachable from the
   2023 // marking stack have been marked, or are overflowed in the heap.
   2024 template <MarkCompactMode mode>
   2025 void MarkCompactCollector::EmptyMarkingDeque() {
   2026   while (!marking_deque()->IsEmpty()) {
   2027     HeapObject* object = marking_deque()->Pop();
   2028 
   2029     DCHECK(!object->IsFiller());
   2030     DCHECK(object->IsHeapObject());
   2031     DCHECK(heap()->Contains(object));
   2032     DCHECK(!ObjectMarking::IsWhite(object));
   2033 
   2034     Map* map = object->map();
   2035     switch (mode) {
   2036       case MarkCompactMode::FULL: {
   2037         MarkObject(map);
   2038         MarkCompactMarkingVisitor::IterateBody(map, object);
   2039       } break;
   2040       case MarkCompactMode::YOUNG_GENERATION: {
   2041         DCHECK(ObjectMarking::IsBlack(object));
   2042         StaticYoungGenerationMarkingVisitor::IterateBody(map, object);
   2043       } break;
   2044     }
   2045   }
   2046 }
   2047 
   2048 
   2049 // Sweep the heap for overflowed objects, clear their overflow bits, and
   2050 // push them on the marking stack.  Stop early if the marking stack fills
   2051 // before sweeping completes.  If sweeping completes, there are no remaining
   2052 // overflowed objects in the heap so the overflow flag on the markings stack
   2053 // is cleared.
   2054 template <MarkCompactMode mode>
   2055 void MarkCompactCollector::RefillMarkingDeque() {
   2056   isolate()->CountUsage(v8::Isolate::UseCounterFeature::kMarkDequeOverflow);
   2057   DCHECK(marking_deque()->overflowed());
   2058 
   2059   DiscoverGreyObjectsInNewSpace();
   2060   if (marking_deque()->IsFull()) return;
   2061 
   2062   if (mode == MarkCompactMode::FULL) {
   2063     DiscoverGreyObjectsInSpace(heap()->old_space());
   2064     if (marking_deque()->IsFull()) return;
   2065     DiscoverGreyObjectsInSpace(heap()->code_space());
   2066     if (marking_deque()->IsFull()) return;
   2067     DiscoverGreyObjectsInSpace(heap()->map_space());
   2068     if (marking_deque()->IsFull()) return;
   2069     LargeObjectIterator lo_it(heap()->lo_space());
   2070     DiscoverGreyObjectsWithIterator(&lo_it);
   2071     if (marking_deque()->IsFull()) return;
   2072   }
   2073 
   2074   marking_deque()->ClearOverflowed();
   2075 }
   2076 
   2077 
   2078 // Mark all objects reachable (transitively) from objects on the marking
   2079 // stack.  Before: the marking stack contains zero or more heap object
   2080 // pointers.  After: the marking stack is empty and there are no overflowed
   2081 // objects in the heap.
   2082 template <MarkCompactMode mode>
   2083 void MarkCompactCollector::ProcessMarkingDeque() {
   2084   EmptyMarkingDeque<mode>();
   2085   while (marking_deque()->overflowed()) {
   2086     RefillMarkingDeque<mode>();
   2087     EmptyMarkingDeque<mode>();
   2088   }
   2089   DCHECK(marking_deque()->IsEmpty());
   2090 }
   2091 
   2092 // Mark all objects reachable (transitively) from objects on the marking
   2093 // stack including references only considered in the atomic marking pause.
   2094 void MarkCompactCollector::ProcessEphemeralMarking(
   2095     ObjectVisitor* visitor, bool only_process_harmony_weak_collections) {
   2096   DCHECK(marking_deque()->IsEmpty() && !marking_deque()->overflowed());
   2097   bool work_to_do = true;
   2098   while (work_to_do) {
   2099     if (!only_process_harmony_weak_collections) {
   2100       if (heap_->local_embedder_heap_tracer()->InUse()) {
   2101         TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_WRAPPER_TRACING);
   2102         heap_->local_embedder_heap_tracer()->RegisterWrappersWithRemoteTracer();
   2103         heap_->local_embedder_heap_tracer()->Trace(
   2104             0,
   2105             EmbedderHeapTracer::AdvanceTracingActions(
   2106                 EmbedderHeapTracer::ForceCompletionAction::FORCE_COMPLETION));
   2107       } else {
   2108         TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_OBJECT_GROUPING);
   2109         isolate()->global_handles()->IterateObjectGroups(
   2110             visitor, &IsUnmarkedHeapObjectWithHeap);
   2111         MarkImplicitRefGroups(&MarkCompactMarkingVisitor::MarkObject);
   2112       }
   2113     } else {
   2114       // TODO(mlippautz): We currently do not trace through blink when
   2115       // discovering new objects reachable from weak roots (that have been made
   2116       // strong). This is a limitation of not having a separate handle type
   2117       // that doesn't require zapping before this phase. See crbug.com/668060.
   2118       heap_->local_embedder_heap_tracer()->ClearCachedWrappersToTrace();
   2119     }
   2120     ProcessWeakCollections();
   2121     work_to_do = !marking_deque()->IsEmpty();
   2122     ProcessMarkingDeque<MarkCompactMode::FULL>();
   2123   }
   2124   CHECK(marking_deque()->IsEmpty());
   2125   CHECK_EQ(0, heap()->local_embedder_heap_tracer()->NumberOfWrappersToTrace());
   2126 }
   2127 
   2128 void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor) {
   2129   for (StackFrameIterator it(isolate(), isolate()->thread_local_top());
   2130        !it.done(); it.Advance()) {
   2131     if (it.frame()->type() == StackFrame::JAVA_SCRIPT) {
   2132       return;
   2133     }
   2134     if (it.frame()->type() == StackFrame::OPTIMIZED) {
   2135       Code* code = it.frame()->LookupCode();
   2136       if (!code->CanDeoptAt(it.frame()->pc())) {
   2137         Code::BodyDescriptor::IterateBody(code, visitor);
   2138       }
   2139       ProcessMarkingDeque<MarkCompactMode::FULL>();
   2140       return;
   2141     }
   2142   }
   2143 }
   2144 
   2145 void MarkingDeque::SetUp() {
   2146   backing_store_ = new base::VirtualMemory(kMaxSize);
   2147   backing_store_committed_size_ = 0;
   2148   if (backing_store_ == nullptr) {
   2149     V8::FatalProcessOutOfMemory("MarkingDeque::SetUp");
   2150   }
   2151 }
   2152 
   2153 void MarkingDeque::TearDown() {
   2154   delete backing_store_;
   2155 }
   2156 
   2157 void MarkingDeque::StartUsing() {
   2158   base::LockGuard<base::Mutex> guard(&mutex_);
   2159   if (in_use_) {
   2160     // This can happen in mark-compact GC if the incremental marker already
   2161     // started using the marking deque.
   2162     return;
   2163   }
   2164   in_use_ = true;
   2165   EnsureCommitted();
   2166   array_ = reinterpret_cast<HeapObject**>(backing_store_->address());
   2167   size_t size = FLAG_force_marking_deque_overflows
   2168                     ? 64 * kPointerSize
   2169                     : backing_store_committed_size_;
   2170   DCHECK(
   2171       base::bits::IsPowerOfTwo32(static_cast<uint32_t>(size / kPointerSize)));
   2172   mask_ = static_cast<int>((size / kPointerSize) - 1);
   2173   top_ = bottom_ = 0;
   2174   overflowed_ = false;
   2175 }
   2176 
   2177 void MarkingDeque::StopUsing() {
   2178   base::LockGuard<base::Mutex> guard(&mutex_);
   2179   if (!in_use_) return;
   2180   DCHECK(IsEmpty());
   2181   DCHECK(!overflowed_);
   2182   top_ = bottom_ = mask_ = 0;
   2183   in_use_ = false;
   2184   if (FLAG_concurrent_sweeping) {
   2185     StartUncommitTask();
   2186   } else {
   2187     Uncommit();
   2188   }
   2189 }
   2190 
   2191 void MarkingDeque::Clear() {
   2192   DCHECK(in_use_);
   2193   top_ = bottom_ = 0;
   2194   overflowed_ = false;
   2195 }
   2196 
   2197 void MarkingDeque::Uncommit() {
   2198   DCHECK(!in_use_);
   2199   bool success = backing_store_->Uncommit(backing_store_->address(),
   2200                                           backing_store_committed_size_);
   2201   backing_store_committed_size_ = 0;
   2202   CHECK(success);
   2203 }
   2204 
   2205 void MarkingDeque::EnsureCommitted() {
   2206   DCHECK(in_use_);
   2207   if (backing_store_committed_size_ > 0) return;
   2208 
   2209   for (size_t size = kMaxSize; size >= kMinSize; size /= 2) {
   2210     if (backing_store_->Commit(backing_store_->address(), size, false)) {
   2211       backing_store_committed_size_ = size;
   2212       break;
   2213     }
   2214   }
   2215   if (backing_store_committed_size_ == 0) {
   2216     V8::FatalProcessOutOfMemory("MarkingDeque::EnsureCommitted");
   2217   }
   2218 }
   2219 
   2220 void MarkingDeque::StartUncommitTask() {
   2221   if (!uncommit_task_pending_) {
   2222     uncommit_task_pending_ = true;
   2223     UncommitTask* task = new UncommitTask(heap_->isolate(), this);
   2224     V8::GetCurrentPlatform()->CallOnBackgroundThread(
   2225         task, v8::Platform::kShortRunningTask);
   2226   }
   2227 }
   2228 
   2229 class MarkCompactCollector::ObjectStatsVisitor
   2230     : public MarkCompactCollector::HeapObjectVisitor {
   2231  public:
   2232   ObjectStatsVisitor(Heap* heap, ObjectStats* live_stats,
   2233                      ObjectStats* dead_stats)
   2234       : live_collector_(heap, live_stats), dead_collector_(heap, dead_stats) {
   2235     DCHECK_NOT_NULL(live_stats);
   2236     DCHECK_NOT_NULL(dead_stats);
   2237     // Global objects are roots and thus recorded as live.
   2238     live_collector_.CollectGlobalStatistics();
   2239   }
   2240 
   2241   bool Visit(HeapObject* obj) override {
   2242     if (ObjectMarking::IsBlack(obj)) {
   2243       live_collector_.CollectStatistics(obj);
   2244     } else {
   2245       DCHECK(!ObjectMarking::IsGrey(obj));
   2246       dead_collector_.CollectStatistics(obj);
   2247     }
   2248     return true;
   2249   }
   2250 
   2251  private:
   2252   ObjectStatsCollector live_collector_;
   2253   ObjectStatsCollector dead_collector_;
   2254 };
   2255 
   2256 void MarkCompactCollector::VisitAllObjects(HeapObjectVisitor* visitor) {
   2257   SpaceIterator space_it(heap());
   2258   HeapObject* obj = nullptr;
   2259   while (space_it.has_next()) {
   2260     std::unique_ptr<ObjectIterator> it(space_it.next()->GetObjectIterator());
   2261     ObjectIterator* obj_it = it.get();
   2262     while ((obj = obj_it->Next()) != nullptr) {
   2263       visitor->Visit(obj);
   2264     }
   2265   }
   2266 }
   2267 
   2268 void MarkCompactCollector::RecordObjectStats() {
   2269   if (V8_UNLIKELY(FLAG_gc_stats)) {
   2270     heap()->CreateObjectStats();
   2271     ObjectStatsVisitor visitor(heap(), heap()->live_object_stats_,
   2272                                heap()->dead_object_stats_);
   2273     VisitAllObjects(&visitor);
   2274     if (V8_UNLIKELY(FLAG_gc_stats &
   2275                     v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
   2276       std::stringstream live, dead;
   2277       heap()->live_object_stats_->Dump(live);
   2278       heap()->dead_object_stats_->Dump(dead);
   2279       TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("v8.gc_stats"),
   2280                            "V8.GC_Objects_Stats", TRACE_EVENT_SCOPE_THREAD,
   2281                            "live", TRACE_STR_COPY(live.str().c_str()), "dead",
   2282                            TRACE_STR_COPY(dead.str().c_str()));
   2283     }
   2284     if (FLAG_trace_gc_object_stats) {
   2285       heap()->live_object_stats_->PrintJSON("live");
   2286       heap()->dead_object_stats_->PrintJSON("dead");
   2287     }
   2288     heap()->live_object_stats_->CheckpointObjectStats();
   2289     heap()->dead_object_stats_->ClearObjectStats();
   2290   }
   2291 }
   2292 
   2293 SlotCallbackResult MarkCompactCollector::CheckAndMarkObject(
   2294     Heap* heap, Address slot_address) {
   2295   Object* object = *reinterpret_cast<Object**>(slot_address);
   2296   if (heap->InNewSpace(object)) {
   2297     // Marking happens before flipping the young generation, so the object
   2298     // has to be in ToSpace.
   2299     DCHECK(heap->InToSpace(object));
   2300     HeapObject* heap_object = reinterpret_cast<HeapObject*>(object);
   2301     if (ObjectMarking::IsBlackOrGrey(heap_object)) {
   2302       return KEEP_SLOT;
   2303     }
   2304     ObjectMarking::WhiteToBlack(heap_object);
   2305     StaticYoungGenerationMarkingVisitor::IterateBody(heap_object->map(),
   2306                                                      heap_object);
   2307     return KEEP_SLOT;
   2308   }
   2309   return REMOVE_SLOT;
   2310 }
   2311 
   2312 static bool IsUnmarkedObject(Heap* heap, Object** p) {
   2313   DCHECK_IMPLIES(heap->InNewSpace(*p), heap->InToSpace(*p));
   2314   return heap->InNewSpace(*p) && !ObjectMarking::IsBlack(HeapObject::cast(*p));
   2315 }
   2316 
   2317 void MarkCompactCollector::MarkLiveObjectsInYoungGeneration() {
   2318   TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK);
   2319 
   2320   PostponeInterruptsScope postpone(isolate());
   2321 
   2322   StaticYoungGenerationMarkingVisitor::Initialize(heap());
   2323   RootMarkingVisitor<MarkCompactMode::YOUNG_GENERATION> root_visitor(heap());
   2324 
   2325   marking_deque()->StartUsing();
   2326 
   2327   isolate()->global_handles()->IdentifyWeakUnmodifiedObjects(
   2328       &Heap::IsUnmodifiedHeapObject);
   2329 
   2330   {
   2331     TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK_ROOTS);
   2332     heap()->IterateRoots(&root_visitor, VISIT_ALL_IN_SCAVENGE);
   2333     ProcessMarkingDeque<MarkCompactMode::YOUNG_GENERATION>();
   2334   }
   2335 
   2336   {
   2337     TRACE_GC(heap()->tracer(),
   2338              GCTracer::Scope::MINOR_MC_MARK_OLD_TO_NEW_POINTERS);
   2339     RememberedSet<OLD_TO_NEW>::Iterate(heap(), [this](Address addr) {
   2340       return CheckAndMarkObject(heap(), addr);
   2341     });
   2342     RememberedSet<OLD_TO_NEW>::IterateTyped(
   2343         heap(), [this](SlotType type, Address host_addr, Address addr) {
   2344           return UpdateTypedSlotHelper::UpdateTypedSlot(
   2345               isolate(), type, addr, [this](Object** addr) {
   2346                 return CheckAndMarkObject(heap(),
   2347                                           reinterpret_cast<Address>(addr));
   2348               });
   2349         });
   2350     ProcessMarkingDeque<MarkCompactMode::YOUNG_GENERATION>();
   2351   }
   2352 
   2353   {
   2354     TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK_WEAK);
   2355     heap()->VisitEncounteredWeakCollections(&root_visitor);
   2356     ProcessMarkingDeque<MarkCompactMode::YOUNG_GENERATION>();
   2357   }
   2358 
   2359   if (is_code_flushing_enabled()) {
   2360     TRACE_GC(heap()->tracer(),
   2361              GCTracer::Scope::MINOR_MC_MARK_CODE_FLUSH_CANDIDATES);
   2362     code_flusher()->IteratePointersToFromSpace(&root_visitor);
   2363     ProcessMarkingDeque<MarkCompactMode::YOUNG_GENERATION>();
   2364   }
   2365 
   2366   {
   2367     TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK_GLOBAL_HANDLES);
   2368     isolate()->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending(
   2369         &IsUnmarkedObject);
   2370     isolate()
   2371         ->global_handles()
   2372         ->IterateNewSpaceWeakUnmodifiedRoots<GlobalHandles::VISIT_OTHERS>(
   2373             &root_visitor);
   2374     ProcessMarkingDeque<MarkCompactMode::YOUNG_GENERATION>();
   2375   }
   2376 
   2377   marking_deque()->StopUsing();
   2378 }
   2379 
   2380 void MarkCompactCollector::MarkLiveObjects() {
   2381   TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK);
   2382   // The recursive GC marker detects when it is nearing stack overflow,
   2383   // and switches to a different marking system.  JS interrupts interfere
   2384   // with the C stack limit check.
   2385   PostponeInterruptsScope postpone(isolate());
   2386 
   2387   {
   2388     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_FINISH_INCREMENTAL);
   2389     IncrementalMarking* incremental_marking = heap_->incremental_marking();
   2390     if (was_marked_incrementally_) {
   2391       incremental_marking->Finalize();
   2392     } else {
   2393       CHECK(incremental_marking->IsStopped());
   2394     }
   2395   }
   2396 
   2397 #ifdef DEBUG
   2398   DCHECK(state_ == PREPARE_GC);
   2399   state_ = MARK_LIVE_OBJECTS;
   2400 #endif
   2401 
   2402   marking_deque()->StartUsing();
   2403 
   2404   heap_->local_embedder_heap_tracer()->EnterFinalPause();
   2405 
   2406   {
   2407     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_PREPARE_CODE_FLUSH);
   2408     PrepareForCodeFlushing();
   2409   }
   2410 
   2411   RootMarkingVisitor<MarkCompactMode::FULL> root_visitor(heap());
   2412 
   2413   {
   2414     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_ROOTS);
   2415     MarkRoots(&root_visitor);
   2416     ProcessTopOptimizedFrame(&root_visitor);
   2417   }
   2418 
   2419   {
   2420     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_WEAK_CLOSURE);
   2421 
   2422     // The objects reachable from the roots are marked, yet unreachable
   2423     // objects are unmarked.  Mark objects reachable due to host
   2424     // application specific logic or through Harmony weak maps.
   2425     {
   2426       TRACE_GC(heap()->tracer(),
   2427                GCTracer::Scope::MC_MARK_WEAK_CLOSURE_EPHEMERAL);
   2428       ProcessEphemeralMarking(&root_visitor, false);
   2429     }
   2430 
   2431     // The objects reachable from the roots, weak maps or object groups
   2432     // are marked. Objects pointed to only by weak global handles cannot be
   2433     // immediately reclaimed. Instead, we have to mark them as pending and mark
   2434     // objects reachable from them.
   2435     //
   2436     // First we identify nonlive weak handles and mark them as pending
   2437     // destruction.
   2438     {
   2439       TRACE_GC(heap()->tracer(),
   2440                GCTracer::Scope::MC_MARK_WEAK_CLOSURE_WEAK_HANDLES);
   2441       heap()->isolate()->global_handles()->IdentifyWeakHandles(
   2442           &IsUnmarkedHeapObject);
   2443       ProcessMarkingDeque<MarkCompactMode::FULL>();
   2444     }
   2445     // Then we mark the objects.
   2446 
   2447     {
   2448       TRACE_GC(heap()->tracer(),
   2449                GCTracer::Scope::MC_MARK_WEAK_CLOSURE_WEAK_ROOTS);
   2450       heap()->isolate()->global_handles()->IterateWeakRoots(&root_visitor);
   2451       ProcessMarkingDeque<MarkCompactMode::FULL>();
   2452     }
   2453 
   2454     // Repeat Harmony weak maps marking to mark unmarked objects reachable from
   2455     // the weak roots we just marked as pending destruction.
   2456     //
   2457     // We only process harmony collections, as all object groups have been fully
   2458     // processed and no weakly reachable node can discover new objects groups.
   2459     {
   2460       TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_WEAK_CLOSURE_HARMONY);
   2461       ProcessEphemeralMarking(&root_visitor, true);
   2462       {
   2463         TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_WRAPPER_EPILOGUE);
   2464         heap()->local_embedder_heap_tracer()->TraceEpilogue();
   2465       }
   2466     }
   2467   }
   2468 }
   2469 
   2470 
   2471 void MarkCompactCollector::ClearNonLiveReferences() {
   2472   TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR);
   2473 
   2474   {
   2475     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_STRING_TABLE);
   2476 
   2477     // Prune the string table removing all strings only pointed to by the
   2478     // string table.  Cannot use string_table() here because the string
   2479     // table is marked.
   2480     StringTable* string_table = heap()->string_table();
   2481     InternalizedStringTableCleaner internalized_visitor(heap(), string_table);
   2482     string_table->IterateElements(&internalized_visitor);
   2483     string_table->ElementsRemoved(internalized_visitor.PointersRemoved());
   2484 
   2485     ExternalStringTableCleaner external_visitor(heap(), nullptr);
   2486     heap()->external_string_table_.IterateAll(&external_visitor);
   2487     heap()->external_string_table_.CleanUpAll();
   2488   }
   2489 
   2490   {
   2491     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_WEAK_LISTS);
   2492     // Process the weak references.
   2493     MarkCompactWeakObjectRetainer mark_compact_object_retainer;
   2494     heap()->ProcessAllWeakReferences(&mark_compact_object_retainer);
   2495   }
   2496 
   2497   {
   2498     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_GLOBAL_HANDLES);
   2499 
   2500     // Remove object groups after marking phase.
   2501     heap()->isolate()->global_handles()->RemoveObjectGroups();
   2502     heap()->isolate()->global_handles()->RemoveImplicitRefGroups();
   2503   }
   2504 
   2505   // Flush code from collected candidates.
   2506   if (is_code_flushing_enabled()) {
   2507     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_CODE_FLUSH);
   2508     code_flusher_->ProcessCandidates();
   2509   }
   2510 
   2511 
   2512   DependentCode* dependent_code_list;
   2513   Object* non_live_map_list;
   2514   ClearWeakCells(&non_live_map_list, &dependent_code_list);
   2515 
   2516   {
   2517     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_MAPS);
   2518     ClearSimpleMapTransitions(non_live_map_list);
   2519     ClearFullMapTransitions();
   2520   }
   2521 
   2522   MarkDependentCodeForDeoptimization(dependent_code_list);
   2523 
   2524   ClearWeakCollections();
   2525 }
   2526 
   2527 
   2528 void MarkCompactCollector::MarkDependentCodeForDeoptimization(
   2529     DependentCode* list_head) {
   2530   TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_DEPENDENT_CODE);
   2531   Isolate* isolate = this->isolate();
   2532   DependentCode* current = list_head;
   2533   while (current->length() > 0) {
   2534     have_code_to_deoptimize_ |= current->MarkCodeForDeoptimization(
   2535         isolate, DependentCode::kWeakCodeGroup);
   2536     current = current->next_link();
   2537   }
   2538 
   2539   {
   2540     ArrayList* list = heap_->weak_new_space_object_to_code_list();
   2541     int counter = 0;
   2542     for (int i = 0; i < list->Length(); i += 2) {
   2543       WeakCell* obj = WeakCell::cast(list->Get(i));
   2544       WeakCell* dep = WeakCell::cast(list->Get(i + 1));
   2545       if (obj->cleared() || dep->cleared()) {
   2546         if (!dep->cleared()) {
   2547           Code* code = Code::cast(dep->value());
   2548           if (!code->marked_for_deoptimization()) {
   2549             DependentCode::SetMarkedForDeoptimization(
   2550                 code, DependentCode::DependencyGroup::kWeakCodeGroup);
   2551             code->InvalidateEmbeddedObjects();
   2552             have_code_to_deoptimize_ = true;
   2553           }
   2554         }
   2555       } else {
   2556         // We record the slot manually because marking is finished at this
   2557         // point and the write barrier would bailout.
   2558         list->Set(counter, obj, SKIP_WRITE_BARRIER);
   2559         RecordSlot(list, list->Slot(counter), obj);
   2560         counter++;
   2561         list->Set(counter, dep, SKIP_WRITE_BARRIER);
   2562         RecordSlot(list, list->Slot(counter), dep);
   2563         counter++;
   2564       }
   2565     }
   2566   }
   2567 
   2568   WeakHashTable* table = heap_->weak_object_to_code_table();
   2569   uint32_t capacity = table->Capacity();
   2570   for (uint32_t i = 0; i < capacity; i++) {
   2571     uint32_t key_index = table->EntryToIndex(i);
   2572     Object* key = table->get(key_index);
   2573     if (!table->IsKey(isolate, key)) continue;
   2574     uint32_t value_index = table->EntryToValueIndex(i);
   2575     Object* value = table->get(value_index);
   2576     DCHECK(key->IsWeakCell());
   2577     if (WeakCell::cast(key)->cleared()) {
   2578       have_code_to_deoptimize_ |=
   2579           DependentCode::cast(value)->MarkCodeForDeoptimization(
   2580               isolate, DependentCode::kWeakCodeGroup);
   2581       table->set(key_index, heap_->the_hole_value());
   2582       table->set(value_index, heap_->the_hole_value());
   2583       table->ElementRemoved();
   2584     }
   2585   }
   2586 }
   2587 
   2588 
   2589 void MarkCompactCollector::ClearSimpleMapTransitions(
   2590     Object* non_live_map_list) {
   2591   Object* the_hole_value = heap()->the_hole_value();
   2592   Object* weak_cell_obj = non_live_map_list;
   2593   while (weak_cell_obj != Smi::kZero) {
   2594     WeakCell* weak_cell = WeakCell::cast(weak_cell_obj);
   2595     Map* map = Map::cast(weak_cell->value());
   2596     DCHECK(ObjectMarking::IsWhite(map));
   2597     Object* potential_parent = map->constructor_or_backpointer();
   2598     if (potential_parent->IsMap()) {
   2599       Map* parent = Map::cast(potential_parent);
   2600       if (ObjectMarking::IsBlackOrGrey(parent) &&
   2601           parent->raw_transitions() == weak_cell) {
   2602         ClearSimpleMapTransition(parent, map);
   2603       }
   2604     }
   2605     weak_cell->clear();
   2606     weak_cell_obj = weak_cell->next();
   2607     weak_cell->clear_next(the_hole_value);
   2608   }
   2609 }
   2610 
   2611 
   2612 void MarkCompactCollector::ClearSimpleMapTransition(Map* map,
   2613                                                     Map* dead_transition) {
   2614   // A previously existing simple transition (stored in a WeakCell) is going
   2615   // to be cleared. Clear the useless cell pointer, and take ownership
   2616   // of the descriptor array.
   2617   map->set_raw_transitions(Smi::kZero);
   2618   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
   2619   DescriptorArray* descriptors = map->instance_descriptors();
   2620   if (descriptors == dead_transition->instance_descriptors() &&
   2621       number_of_own_descriptors > 0) {
   2622     TrimDescriptorArray(map, descriptors);
   2623     DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
   2624     map->set_owns_descriptors(true);
   2625   }
   2626 }
   2627 
   2628 
   2629 void MarkCompactCollector::ClearFullMapTransitions() {
   2630   HeapObject* undefined = heap()->undefined_value();
   2631   Object* obj = heap()->encountered_transition_arrays();
   2632   while (obj != Smi::kZero) {
   2633     TransitionArray* array = TransitionArray::cast(obj);
   2634     int num_transitions = array->number_of_entries();
   2635     DCHECK_EQ(TransitionArray::NumberOfTransitions(array), num_transitions);
   2636     if (num_transitions > 0) {
   2637       Map* map = array->GetTarget(0);
   2638       Map* parent = Map::cast(map->constructor_or_backpointer());
   2639       bool parent_is_alive = ObjectMarking::IsBlackOrGrey(parent);
   2640       DescriptorArray* descriptors =
   2641           parent_is_alive ? parent->instance_descriptors() : nullptr;
   2642       bool descriptors_owner_died =
   2643           CompactTransitionArray(parent, array, descriptors);
   2644       if (descriptors_owner_died) {
   2645         TrimDescriptorArray(parent, descriptors);
   2646       }
   2647     }
   2648     obj = array->next_link();
   2649     array->set_next_link(undefined, SKIP_WRITE_BARRIER);
   2650   }
   2651   heap()->set_encountered_transition_arrays(Smi::kZero);
   2652 }
   2653 
   2654 
   2655 bool MarkCompactCollector::CompactTransitionArray(
   2656     Map* map, TransitionArray* transitions, DescriptorArray* descriptors) {
   2657   int num_transitions = transitions->number_of_entries();
   2658   bool descriptors_owner_died = false;
   2659   int transition_index = 0;
   2660   // Compact all live transitions to the left.
   2661   for (int i = 0; i < num_transitions; ++i) {
   2662     Map* target = transitions->GetTarget(i);
   2663     DCHECK_EQ(target->constructor_or_backpointer(), map);
   2664     if (ObjectMarking::IsWhite(target)) {
   2665       if (descriptors != nullptr &&
   2666           target->instance_descriptors() == descriptors) {
   2667         descriptors_owner_died = true;
   2668       }
   2669     } else {
   2670       if (i != transition_index) {
   2671         Name* key = transitions->GetKey(i);
   2672         transitions->SetKey(transition_index, key);
   2673         Object** key_slot = transitions->GetKeySlot(transition_index);
   2674         RecordSlot(transitions, key_slot, key);
   2675         // Target slots do not need to be recorded since maps are not compacted.
   2676         transitions->SetTarget(transition_index, transitions->GetTarget(i));
   2677       }
   2678       transition_index++;
   2679     }
   2680   }
   2681   // If there are no transitions to be cleared, return.
   2682   if (transition_index == num_transitions) {
   2683     DCHECK(!descriptors_owner_died);
   2684     return false;
   2685   }
   2686   // Note that we never eliminate a transition array, though we might right-trim
   2687   // such that number_of_transitions() == 0. If this assumption changes,
   2688   // TransitionArray::Insert() will need to deal with the case that a transition
   2689   // array disappeared during GC.
   2690   int trim = TransitionArray::Capacity(transitions) - transition_index;
   2691   if (trim > 0) {
   2692     heap_->RightTrimFixedArray(transitions,
   2693                                trim * TransitionArray::kTransitionSize);
   2694     transitions->SetNumberOfTransitions(transition_index);
   2695   }
   2696   return descriptors_owner_died;
   2697 }
   2698 
   2699 
   2700 void MarkCompactCollector::TrimDescriptorArray(Map* map,
   2701                                                DescriptorArray* descriptors) {
   2702   int number_of_own_descriptors = map->NumberOfOwnDescriptors();
   2703   if (number_of_own_descriptors == 0) {
   2704     DCHECK(descriptors == heap_->empty_descriptor_array());
   2705     return;
   2706   }
   2707 
   2708   int number_of_descriptors = descriptors->number_of_descriptors_storage();
   2709   int to_trim = number_of_descriptors - number_of_own_descriptors;
   2710   if (to_trim > 0) {
   2711     heap_->RightTrimFixedArray(descriptors,
   2712                                to_trim * DescriptorArray::kEntrySize);
   2713     descriptors->SetNumberOfDescriptors(number_of_own_descriptors);
   2714 
   2715     if (descriptors->HasEnumCache()) TrimEnumCache(map, descriptors);
   2716     descriptors->Sort();
   2717 
   2718     if (FLAG_unbox_double_fields) {
   2719       LayoutDescriptor* layout_descriptor = map->layout_descriptor();
   2720       layout_descriptor = layout_descriptor->Trim(heap_, map, descriptors,
   2721                                                   number_of_own_descriptors);
   2722       SLOW_DCHECK(layout_descriptor->IsConsistentWithMap(map, true));
   2723     }
   2724   }
   2725   DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
   2726   map->set_owns_descriptors(true);
   2727 }
   2728 
   2729 
   2730 void MarkCompactCollector::TrimEnumCache(Map* map,
   2731                                          DescriptorArray* descriptors) {
   2732   int live_enum = map->EnumLength();
   2733   if (live_enum == kInvalidEnumCacheSentinel) {
   2734     live_enum =
   2735         map->NumberOfDescribedProperties(OWN_DESCRIPTORS, ENUMERABLE_STRINGS);
   2736   }
   2737   if (live_enum == 0) return descriptors->ClearEnumCache();
   2738 
   2739   FixedArray* enum_cache = descriptors->GetEnumCache();
   2740 
   2741   int to_trim = enum_cache->length() - live_enum;
   2742   if (to_trim <= 0) return;
   2743   heap_->RightTrimFixedArray(descriptors->GetEnumCache(), to_trim);
   2744 
   2745   if (!descriptors->HasEnumIndicesCache()) return;
   2746   FixedArray* enum_indices_cache = descriptors->GetEnumIndicesCache();
   2747   heap_->RightTrimFixedArray(enum_indices_cache, to_trim);
   2748 }
   2749 
   2750 
   2751 void MarkCompactCollector::ProcessWeakCollections() {
   2752   Object* weak_collection_obj = heap()->encountered_weak_collections();
   2753   while (weak_collection_obj != Smi::kZero) {
   2754     JSWeakCollection* weak_collection =
   2755         reinterpret_cast<JSWeakCollection*>(weak_collection_obj);
   2756     DCHECK(ObjectMarking::IsBlackOrGrey(weak_collection));
   2757     if (weak_collection->table()->IsHashTable()) {
   2758       ObjectHashTable* table = ObjectHashTable::cast(weak_collection->table());
   2759       for (int i = 0; i < table->Capacity(); i++) {
   2760         if (ObjectMarking::IsBlackOrGrey(HeapObject::cast(table->KeyAt(i)))) {
   2761           Object** key_slot =
   2762               table->RawFieldOfElementAt(ObjectHashTable::EntryToIndex(i));
   2763           RecordSlot(table, key_slot, *key_slot);
   2764           Object** value_slot =
   2765               table->RawFieldOfElementAt(ObjectHashTable::EntryToValueIndex(i));
   2766           MarkCompactMarkingVisitor::MarkObjectByPointer(this, table,
   2767                                                          value_slot);
   2768         }
   2769       }
   2770     }
   2771     weak_collection_obj = weak_collection->next();
   2772   }
   2773 }
   2774 
   2775 
   2776 void MarkCompactCollector::ClearWeakCollections() {
   2777   TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_WEAK_COLLECTIONS);
   2778   Object* weak_collection_obj = heap()->encountered_weak_collections();
   2779   while (weak_collection_obj != Smi::kZero) {
   2780     JSWeakCollection* weak_collection =
   2781         reinterpret_cast<JSWeakCollection*>(weak_collection_obj);
   2782     DCHECK(ObjectMarking::IsBlackOrGrey(weak_collection));
   2783     if (weak_collection->table()->IsHashTable()) {
   2784       ObjectHashTable* table = ObjectHashTable::cast(weak_collection->table());
   2785       for (int i = 0; i < table->Capacity(); i++) {
   2786         HeapObject* key = HeapObject::cast(table->KeyAt(i));
   2787         if (!ObjectMarking::IsBlackOrGrey(key)) {
   2788           table->RemoveEntry(i);
   2789         }
   2790       }
   2791     }
   2792     weak_collection_obj = weak_collection->next();
   2793     weak_collection->set_next(heap()->undefined_value());
   2794   }
   2795   heap()->set_encountered_weak_collections(Smi::kZero);
   2796 }
   2797 
   2798 
   2799 void MarkCompactCollector::AbortWeakCollections() {
   2800   Object* weak_collection_obj = heap()->encountered_weak_collections();
   2801   while (weak_collection_obj != Smi::kZero) {
   2802     JSWeakCollection* weak_collection =
   2803         reinterpret_cast<JSWeakCollection*>(weak_collection_obj);
   2804     weak_collection_obj = weak_collection->next();
   2805     weak_collection->set_next(heap()->undefined_value());
   2806   }
   2807   heap()->set_encountered_weak_collections(Smi::kZero);
   2808 }
   2809 
   2810 
   2811 void MarkCompactCollector::ClearWeakCells(Object** non_live_map_list,
   2812                                           DependentCode** dependent_code_list) {
   2813   Heap* heap = this->heap();
   2814   TRACE_GC(heap->tracer(), GCTracer::Scope::MC_CLEAR_WEAK_CELLS);
   2815   Object* weak_cell_obj = heap->encountered_weak_cells();
   2816   Object* the_hole_value = heap->the_hole_value();
   2817   DependentCode* dependent_code_head =
   2818       DependentCode::cast(heap->empty_fixed_array());
   2819   Object* non_live_map_head = Smi::kZero;
   2820   while (weak_cell_obj != Smi::kZero) {
   2821     WeakCell* weak_cell = reinterpret_cast<WeakCell*>(weak_cell_obj);
   2822     Object* next_weak_cell = weak_cell->next();
   2823     bool clear_value = true;
   2824     bool clear_next = true;
   2825     // We do not insert cleared weak cells into the list, so the value
   2826     // cannot be a Smi here.
   2827     HeapObject* value = HeapObject::cast(weak_cell->value());
   2828     if (!ObjectMarking::IsBlackOrGrey(value)) {
   2829       // Cells for new-space objects embedded in optimized code are wrapped in
   2830       // WeakCell and put into Heap::weak_object_to_code_table.
   2831       // Such cells do not have any strong references but we want to keep them
   2832       // alive as long as the cell value is alive.
   2833       // TODO(ulan): remove this once we remove Heap::weak_object_to_code_table.
   2834       if (value->IsCell()) {
   2835         Object* cell_value = Cell::cast(value)->value();
   2836         if (cell_value->IsHeapObject() &&
   2837             ObjectMarking::IsBlackOrGrey(HeapObject::cast(cell_value))) {
   2838           // Resurrect the cell.
   2839           ObjectMarking::WhiteToBlack(value);
   2840           Object** slot = HeapObject::RawField(value, Cell::kValueOffset);
   2841           RecordSlot(value, slot, *slot);
   2842           slot = HeapObject::RawField(weak_cell, WeakCell::kValueOffset);
   2843           RecordSlot(weak_cell, slot, *slot);
   2844           clear_value = false;
   2845         }
   2846       }
   2847       if (value->IsMap()) {
   2848         // The map is non-live.
   2849         Map* map = Map::cast(value);
   2850         // Add dependent code to the dependent_code_list.
   2851         DependentCode* candidate = map->dependent_code();
   2852         // We rely on the fact that the weak code group comes first.
   2853         STATIC_ASSERT(DependentCode::kWeakCodeGroup == 0);
   2854         if (candidate->length() > 0 &&
   2855             candidate->group() == DependentCode::kWeakCodeGroup) {
   2856           candidate->set_next_link(dependent_code_head);
   2857           dependent_code_head = candidate;
   2858         }
   2859         // Add the weak cell to the non_live_map list.
   2860         weak_cell->set_next(non_live_map_head);
   2861         non_live_map_head = weak_cell;
   2862         clear_value = false;
   2863         clear_next = false;
   2864       }
   2865     } else {
   2866       // The value of the weak cell is alive.
   2867       Object** slot = HeapObject::RawField(weak_cell, WeakCell::kValueOffset);
   2868       RecordSlot(weak_cell, slot, *slot);
   2869       clear_value = false;
   2870     }
   2871     if (clear_value) {
   2872       weak_cell->clear();
   2873     }
   2874     if (clear_next) {
   2875       weak_cell->clear_next(the_hole_value);
   2876     }
   2877     weak_cell_obj = next_weak_cell;
   2878   }
   2879   heap->set_encountered_weak_cells(Smi::kZero);
   2880   *non_live_map_list = non_live_map_head;
   2881   *dependent_code_list = dependent_code_head;
   2882 }
   2883 
   2884 
   2885 void MarkCompactCollector::AbortWeakCells() {
   2886   Object* the_hole_value = heap()->the_hole_value();
   2887   Object* weak_cell_obj = heap()->encountered_weak_cells();
   2888   while (weak_cell_obj != Smi::kZero) {
   2889     WeakCell* weak_cell = reinterpret_cast<WeakCell*>(weak_cell_obj);
   2890     weak_cell_obj = weak_cell->next();
   2891     weak_cell->clear_next(the_hole_value);
   2892   }
   2893   heap()->set_encountered_weak_cells(Smi::kZero);
   2894 }
   2895 
   2896 
   2897 void MarkCompactCollector::AbortTransitionArrays() {
   2898   HeapObject* undefined = heap()->undefined_value();
   2899   Object* obj = heap()->encountered_transition_arrays();
   2900   while (obj != Smi::kZero) {
   2901     TransitionArray* array = TransitionArray::cast(obj);
   2902     obj = array->next_link();
   2903     array->set_next_link(undefined, SKIP_WRITE_BARRIER);
   2904   }
   2905   heap()->set_encountered_transition_arrays(Smi::kZero);
   2906 }
   2907 
   2908 void MarkCompactCollector::RecordRelocSlot(Code* host, RelocInfo* rinfo,
   2909                                            Object* target) {
   2910   Page* target_page = Page::FromAddress(reinterpret_cast<Address>(target));
   2911   Page* source_page = Page::FromAddress(reinterpret_cast<Address>(host));
   2912   if (target_page->IsEvacuationCandidate() &&
   2913       (rinfo->host() == NULL ||
   2914        !ShouldSkipEvacuationSlotRecording(rinfo->host()))) {
   2915     RelocInfo::Mode rmode = rinfo->rmode();
   2916     Address addr = rinfo->pc();
   2917     SlotType slot_type = SlotTypeForRelocInfoMode(rmode);
   2918     if (rinfo->IsInConstantPool()) {
   2919       addr = rinfo->constant_pool_entry_address();
   2920       if (RelocInfo::IsCodeTarget(rmode)) {
   2921         slot_type = CODE_ENTRY_SLOT;
   2922       } else {
   2923         DCHECK(RelocInfo::IsEmbeddedObject(rmode));
   2924         slot_type = OBJECT_SLOT;
   2925       }
   2926     }
   2927     RememberedSet<OLD_TO_OLD>::InsertTyped(
   2928         source_page, reinterpret_cast<Address>(host), slot_type, addr);
   2929   }
   2930 }
   2931 
   2932 static inline SlotCallbackResult UpdateSlot(Object** slot) {
   2933   Object* obj = reinterpret_cast<Object*>(
   2934       base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot)));
   2935 
   2936   if (obj->IsHeapObject()) {
   2937     HeapObject* heap_obj = HeapObject::cast(obj);
   2938     MapWord map_word = heap_obj->map_word();
   2939     if (map_word.IsForwardingAddress()) {
   2940       DCHECK(heap_obj->GetHeap()->InFromSpace(heap_obj) ||
   2941              MarkCompactCollector::IsOnEvacuationCandidate(heap_obj) ||
   2942              Page::FromAddress(heap_obj->address())
   2943                  ->IsFlagSet(Page::COMPACTION_WAS_ABORTED));
   2944       HeapObject* target = map_word.ToForwardingAddress();
   2945       base::NoBarrier_CompareAndSwap(
   2946           reinterpret_cast<base::AtomicWord*>(slot),
   2947           reinterpret_cast<base::AtomicWord>(obj),
   2948           reinterpret_cast<base::AtomicWord>(target));
   2949       DCHECK(!heap_obj->GetHeap()->InFromSpace(target) &&
   2950              !MarkCompactCollector::IsOnEvacuationCandidate(target));
   2951     }
   2952   }
   2953   return REMOVE_SLOT;
   2954 }
   2955 
   2956 // Visitor for updating pointers from live objects in old spaces to new space.
   2957 // It does not expect to encounter pointers to dead objects.
   2958 class PointersUpdatingVisitor : public ObjectVisitor {
   2959  public:
   2960   void VisitPointer(Object** p) override { UpdateSlot(p); }
   2961 
   2962   void VisitPointers(Object** start, Object** end) override {
   2963     for (Object** p = start; p < end; p++) UpdateSlot(p);
   2964   }
   2965 
   2966   void VisitCell(RelocInfo* rinfo) override {
   2967     UpdateTypedSlotHelper::UpdateCell(rinfo, UpdateSlot);
   2968   }
   2969 
   2970   void VisitEmbeddedPointer(RelocInfo* rinfo) override {
   2971     UpdateTypedSlotHelper::UpdateEmbeddedPointer(rinfo, UpdateSlot);
   2972   }
   2973 
   2974   void VisitCodeTarget(RelocInfo* rinfo) override {
   2975     UpdateTypedSlotHelper::UpdateCodeTarget(rinfo, UpdateSlot);
   2976   }
   2977 
   2978   void VisitCodeEntry(Address entry_address) override {
   2979     UpdateTypedSlotHelper::UpdateCodeEntry(entry_address, UpdateSlot);
   2980   }
   2981 
   2982   void VisitDebugTarget(RelocInfo* rinfo) override {
   2983     UpdateTypedSlotHelper::UpdateDebugTarget(rinfo, UpdateSlot);
   2984   }
   2985 };
   2986 
   2987 static String* UpdateReferenceInExternalStringTableEntry(Heap* heap,
   2988                                                          Object** p) {
   2989   MapWord map_word = HeapObject::cast(*p)->map_word();
   2990 
   2991   if (map_word.IsForwardingAddress()) {
   2992     return String::cast(map_word.ToForwardingAddress());
   2993   }
   2994 
   2995   return String::cast(*p);
   2996 }
   2997 
   2998 void MarkCompactCollector::EvacuatePrologue() {
   2999   // New space.
   3000   NewSpace* new_space = heap()->new_space();
   3001   // Append the list of new space pages to be processed.
   3002   for (Page* p : PageRange(new_space->bottom(), new_space->top())) {
   3003     new_space_evacuation_pages_.Add(p);
   3004   }
   3005   new_space->Flip();
   3006   new_space->ResetAllocationInfo();
   3007 
   3008   // Old space.
   3009   CHECK(old_space_evacuation_pages_.is_empty());
   3010   old_space_evacuation_pages_.Swap(&evacuation_candidates_);
   3011 }
   3012 
   3013 void MarkCompactCollector::EvacuateEpilogue() {
   3014   // New space.
   3015   heap()->new_space()->set_age_mark(heap()->new_space()->top());
   3016   // Old space. Deallocate evacuated candidate pages.
   3017   ReleaseEvacuationCandidates();
   3018 }
   3019 
   3020 class MarkCompactCollector::Evacuator : public Malloced {
   3021  public:
   3022   enum EvacuationMode {
   3023     kObjectsNewToOld,
   3024     kPageNewToOld,
   3025     kObjectsOldToOld,
   3026     kPageNewToNew,
   3027   };
   3028 
   3029   static inline EvacuationMode ComputeEvacuationMode(MemoryChunk* chunk) {
   3030     // Note: The order of checks is important in this function.
   3031     if (chunk->IsFlagSet(MemoryChunk::PAGE_NEW_OLD_PROMOTION))
   3032       return kPageNewToOld;
   3033     if (chunk->IsFlagSet(MemoryChunk::PAGE_NEW_NEW_PROMOTION))
   3034       return kPageNewToNew;
   3035     if (chunk->InNewSpace()) return kObjectsNewToOld;
   3036     DCHECK(chunk->IsEvacuationCandidate());
   3037     return kObjectsOldToOld;
   3038   }
   3039 
   3040   // NewSpacePages with more live bytes than this threshold qualify for fast
   3041   // evacuation.
   3042   static int PageEvacuationThreshold() {
   3043     if (FLAG_page_promotion)
   3044       return FLAG_page_promotion_threshold * Page::kAllocatableMemory / 100;
   3045     return Page::kAllocatableMemory + kPointerSize;
   3046   }
   3047 
   3048   explicit Evacuator(MarkCompactCollector* collector)
   3049       : collector_(collector),
   3050         compaction_spaces_(collector->heap()),
   3051         local_pretenuring_feedback_(kInitialLocalPretenuringFeedbackCapacity),
   3052         new_space_visitor_(collector->heap(), &compaction_spaces_,
   3053                            &local_pretenuring_feedback_),
   3054         new_to_new_page_visitor_(collector->heap(),
   3055                                  &local_pretenuring_feedback_),
   3056         new_to_old_page_visitor_(collector->heap(),
   3057                                  &local_pretenuring_feedback_),
   3058 
   3059         old_space_visitor_(collector->heap(), &compaction_spaces_),
   3060         duration_(0.0),
   3061         bytes_compacted_(0) {}
   3062 
   3063   inline bool EvacuatePage(Page* chunk);
   3064 
   3065   // Merge back locally cached info sequentially. Note that this method needs
   3066   // to be called from the main thread.
   3067   inline void Finalize();
   3068 
   3069   CompactionSpaceCollection* compaction_spaces() { return &compaction_spaces_; }
   3070 
   3071  private:
   3072   static const int kInitialLocalPretenuringFeedbackCapacity = 256;
   3073 
   3074   inline Heap* heap() { return collector_->heap(); }
   3075 
   3076   void ReportCompactionProgress(double duration, intptr_t bytes_compacted) {
   3077     duration_ += duration;
   3078     bytes_compacted_ += bytes_compacted;
   3079   }
   3080 
   3081   MarkCompactCollector* collector_;
   3082 
   3083   // Locally cached collector data.
   3084   CompactionSpaceCollection compaction_spaces_;
   3085   base::HashMap local_pretenuring_feedback_;
   3086 
   3087   // Visitors for the corresponding spaces.
   3088   EvacuateNewSpaceVisitor new_space_visitor_;
   3089   EvacuateNewSpacePageVisitor<PageEvacuationMode::NEW_TO_NEW>
   3090       new_to_new_page_visitor_;
   3091   EvacuateNewSpacePageVisitor<PageEvacuationMode::NEW_TO_OLD>
   3092       new_to_old_page_visitor_;
   3093   EvacuateOldSpaceVisitor old_space_visitor_;
   3094 
   3095   // Book keeping info.
   3096   double duration_;
   3097   intptr_t bytes_compacted_;
   3098 };
   3099 
   3100 bool MarkCompactCollector::Evacuator::EvacuatePage(Page* page) {
   3101   bool success = false;
   3102   DCHECK(page->SweepingDone());
   3103   int saved_live_bytes = page->LiveBytes();
   3104   double evacuation_time = 0.0;
   3105   Heap* heap = page->heap();
   3106   {
   3107     AlwaysAllocateScope always_allocate(heap->isolate());
   3108     TimedScope timed_scope(&evacuation_time);
   3109     switch (ComputeEvacuationMode(page)) {
   3110       case kObjectsNewToOld:
   3111         success = collector_->VisitLiveObjects(page, &new_space_visitor_,
   3112                                                kClearMarkbits);
   3113         DCHECK(success);
   3114         ArrayBufferTracker::ProcessBuffers(
   3115             page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
   3116         break;
   3117       case kPageNewToOld:
   3118         success = collector_->VisitLiveObjects(page, &new_to_old_page_visitor_,
   3119                                                kKeepMarking);
   3120         DCHECK(success);
   3121         new_to_old_page_visitor_.account_moved_bytes(page->LiveBytes());
   3122         // ArrayBufferTracker will be updated during sweeping.
   3123         break;
   3124       case kPageNewToNew:
   3125         success = collector_->VisitLiveObjects(page, &new_to_new_page_visitor_,
   3126                                                kKeepMarking);
   3127         DCHECK(success);
   3128         new_to_new_page_visitor_.account_moved_bytes(page->LiveBytes());
   3129         // ArrayBufferTracker will be updated during sweeping.
   3130         break;
   3131       case kObjectsOldToOld:
   3132         success = collector_->VisitLiveObjects(page, &old_space_visitor_,
   3133                                                kClearMarkbits);
   3134         if (!success) {
   3135           // Aborted compaction page. We have to record slots here, since we
   3136           // might not have recorded them in first place.
   3137           // Note: We mark the page as aborted here to be able to record slots
   3138           // for code objects in |RecordMigratedSlotVisitor|.
   3139           page->SetFlag(Page::COMPACTION_WAS_ABORTED);
   3140           EvacuateRecordOnlyVisitor record_visitor(collector_->heap());
   3141           success =
   3142               collector_->VisitLiveObjects(page, &record_visitor, kKeepMarking);
   3143           ArrayBufferTracker::ProcessBuffers(
   3144               page, ArrayBufferTracker::kUpdateForwardedKeepOthers);
   3145           DCHECK(success);
   3146           // We need to return failure here to indicate that we want this page
   3147           // added to the sweeper.
   3148           success = false;
   3149         } else {
   3150           ArrayBufferTracker::ProcessBuffers(
   3151               page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
   3152         }
   3153         break;
   3154     }
   3155   }
   3156   ReportCompactionProgress(evacuation_time, saved_live_bytes);
   3157   if (FLAG_trace_evacuation) {
   3158     PrintIsolate(heap->isolate(),
   3159                  "evacuation[%p]: page=%p new_space=%d "
   3160                  "page_evacuation=%d executable=%d contains_age_mark=%d "
   3161                  "live_bytes=%d time=%f\n",
   3162                  static_cast<void*>(this), static_cast<void*>(page),
   3163                  page->InNewSpace(),
   3164                  page->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION) ||
   3165                      page->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION),
   3166                  page->IsFlagSet(MemoryChunk::IS_EXECUTABLE),
   3167                  page->Contains(heap->new_space()->age_mark()),
   3168                  saved_live_bytes, evacuation_time);
   3169   }
   3170   return success;
   3171 }
   3172 
   3173 void MarkCompactCollector::Evacuator::Finalize() {
   3174   heap()->old_space()->MergeCompactionSpace(compaction_spaces_.Get(OLD_SPACE));
   3175   heap()->code_space()->MergeCompactionSpace(
   3176       compaction_spaces_.Get(CODE_SPACE));
   3177   heap()->tracer()->AddCompactionEvent(duration_, bytes_compacted_);
   3178   heap()->IncrementPromotedObjectsSize(new_space_visitor_.promoted_size() +
   3179                                        new_to_old_page_visitor_.moved_bytes());
   3180   heap()->IncrementSemiSpaceCopiedObjectSize(
   3181       new_space_visitor_.semispace_copied_size() +
   3182       new_to_new_page_visitor_.moved_bytes());
   3183   heap()->IncrementYoungSurvivorsCounter(
   3184       new_space_visitor_.promoted_size() +
   3185       new_space_visitor_.semispace_copied_size() +
   3186       new_to_old_page_visitor_.moved_bytes() +
   3187       new_to_new_page_visitor_.moved_bytes());
   3188   heap()->MergeAllocationSitePretenuringFeedback(local_pretenuring_feedback_);
   3189 }
   3190 
   3191 int MarkCompactCollector::NumberOfParallelCompactionTasks(int pages,
   3192                                                           intptr_t live_bytes) {
   3193   if (!FLAG_parallel_compaction) return 1;
   3194   // Compute the number of needed tasks based on a target compaction time, the
   3195   // profiled compaction speed and marked live memory.
   3196   //
   3197   // The number of parallel compaction tasks is limited by:
   3198   // - #evacuation pages
   3199   // - #cores
   3200   const double kTargetCompactionTimeInMs = .5;
   3201 
   3202   double compaction_speed =
   3203       heap()->tracer()->CompactionSpeedInBytesPerMillisecond();
   3204 
   3205   const int available_cores = Max(
   3206       1, static_cast<int>(
   3207              V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads()));
   3208   int tasks;
   3209   if (compaction_speed > 0) {
   3210     tasks = 1 + static_cast<int>(live_bytes / compaction_speed /
   3211                                  kTargetCompactionTimeInMs);
   3212   } else {
   3213     tasks = pages;
   3214   }
   3215   const int tasks_capped_pages = Min(pages, tasks);
   3216   return Min(available_cores, tasks_capped_pages);
   3217 }
   3218 
   3219 class EvacuationJobTraits {
   3220  public:
   3221   typedef int* PerPageData;  // Pointer to number of aborted pages.
   3222   typedef MarkCompactCollector::Evacuator* PerTaskData;
   3223 
   3224   static const bool NeedSequentialFinalization = true;
   3225 
   3226   static bool ProcessPageInParallel(Heap* heap, PerTaskData evacuator,
   3227                                     MemoryChunk* chunk, PerPageData) {
   3228     return evacuator->EvacuatePage(reinterpret_cast<Page*>(chunk));
   3229   }
   3230 
   3231   static void FinalizePageSequentially(Heap* heap, MemoryChunk* chunk,
   3232                                        bool success, PerPageData data) {
   3233     using Evacuator = MarkCompactCollector::Evacuator;
   3234     Page* p = static_cast<Page*>(chunk);
   3235     switch (Evacuator::ComputeEvacuationMode(p)) {
   3236       case Evacuator::kPageNewToOld:
   3237         break;
   3238       case Evacuator::kPageNewToNew:
   3239         DCHECK(success);
   3240         break;
   3241       case Evacuator::kObjectsNewToOld:
   3242         DCHECK(success);
   3243         break;
   3244       case Evacuator::kObjectsOldToOld:
   3245         if (success) {
   3246           DCHECK(p->IsEvacuationCandidate());
   3247           DCHECK(p->SweepingDone());
   3248           p->Unlink();
   3249         } else {
   3250           // We have partially compacted the page, i.e., some objects may have
   3251           // moved, others are still in place.
   3252           p->ClearEvacuationCandidate();
   3253           // Slots have already been recorded so we just need to add it to the
   3254           // sweeper, which will happen after updating pointers.
   3255           *data += 1;
   3256         }
   3257         break;
   3258       default:
   3259         UNREACHABLE();
   3260     }
   3261   }
   3262 };
   3263 
   3264 void MarkCompactCollector::EvacuatePagesInParallel() {
   3265   PageParallelJob<EvacuationJobTraits> job(
   3266       heap_, heap_->isolate()->cancelable_task_manager(),
   3267       &page_parallel_job_semaphore_);
   3268 
   3269   int abandoned_pages = 0;
   3270   intptr_t live_bytes = 0;
   3271   for (Page* page : old_space_evacuation_pages_) {
   3272     live_bytes += page->LiveBytes();
   3273     job.AddPage(page, &abandoned_pages);
   3274   }
   3275 
   3276   const bool reduce_memory = heap()->ShouldReduceMemory();
   3277   const Address age_mark = heap()->new_space()->age_mark();
   3278   for (Page* page : new_space_evacuation_pages_) {
   3279     live_bytes += page->LiveBytes();
   3280     if (!reduce_memory && !page->NeverEvacuate() &&
   3281         (page->LiveBytes() > Evacuator::PageEvacuationThreshold()) &&
   3282         !page->Contains(age_mark) &&
   3283         heap()->CanExpandOldGeneration(page->LiveBytes())) {
   3284       if (page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK)) {
   3285         EvacuateNewSpacePageVisitor<NEW_TO_OLD>::Move(page);
   3286       } else {
   3287         EvacuateNewSpacePageVisitor<NEW_TO_NEW>::Move(page);
   3288       }
   3289     }
   3290 
   3291     job.AddPage(page, &abandoned_pages);
   3292   }
   3293   DCHECK_GE(job.NumberOfPages(), 1);
   3294 
   3295   // Used for trace summary.
   3296   double compaction_speed = 0;
   3297   if (FLAG_trace_evacuation) {
   3298     compaction_speed = heap()->tracer()->CompactionSpeedInBytesPerMillisecond();
   3299   }
   3300 
   3301   const int wanted_num_tasks =
   3302       NumberOfParallelCompactionTasks(job.NumberOfPages(), live_bytes);
   3303   Evacuator** evacuators = new Evacuator*[wanted_num_tasks];
   3304   for (int i = 0; i < wanted_num_tasks; i++) {
   3305     evacuators[i] = new Evacuator(this);
   3306   }
   3307   job.Run(wanted_num_tasks, [evacuators](int i) { return evacuators[i]; });
   3308   for (int i = 0; i < wanted_num_tasks; i++) {
   3309     evacuators[i]->Finalize();
   3310     delete evacuators[i];
   3311   }
   3312   delete[] evacuators;
   3313 
   3314   if (FLAG_trace_evacuation) {
   3315     PrintIsolate(isolate(),
   3316                  "%8.0f ms: evacuation-summary: parallel=%s pages=%d "
   3317                  "aborted=%d wanted_tasks=%d tasks=%d cores=%" PRIuS
   3318                  " live_bytes=%" V8PRIdPTR " compaction_speed=%.f\n",
   3319                  isolate()->time_millis_since_init(),
   3320                  FLAG_parallel_compaction ? "yes" : "no", job.NumberOfPages(),
   3321                  abandoned_pages, wanted_num_tasks, job.NumberOfTasks(),
   3322                  V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads(),
   3323                  live_bytes, compaction_speed);
   3324   }
   3325 }
   3326 
   3327 class EvacuationWeakObjectRetainer : public WeakObjectRetainer {
   3328  public:
   3329   virtual Object* RetainAs(Object* object) {
   3330     if (object->IsHeapObject()) {
   3331       HeapObject* heap_object = HeapObject::cast(object);
   3332       MapWord map_word = heap_object->map_word();
   3333       if (map_word.IsForwardingAddress()) {
   3334         return map_word.ToForwardingAddress();
   3335       }
   3336     }
   3337     return object;
   3338   }
   3339 };
   3340 
   3341 MarkCompactCollector::Sweeper::ClearOldToNewSlotsMode
   3342 MarkCompactCollector::Sweeper::GetClearOldToNewSlotsMode(Page* p) {
   3343   AllocationSpace identity = p->owner()->identity();
   3344   if (p->old_to_new_slots() &&
   3345       (identity == OLD_SPACE || identity == MAP_SPACE)) {
   3346     return MarkCompactCollector::Sweeper::CLEAR_REGULAR_SLOTS;
   3347   } else if (p->typed_old_to_new_slots() && identity == CODE_SPACE) {
   3348     return MarkCompactCollector::Sweeper::CLEAR_TYPED_SLOTS;
   3349   }
   3350   return MarkCompactCollector::Sweeper::DO_NOT_CLEAR;
   3351 }
   3352 
   3353 int MarkCompactCollector::Sweeper::RawSweep(
   3354     Page* p, FreeListRebuildingMode free_list_mode,
   3355     FreeSpaceTreatmentMode free_space_mode) {
   3356   Space* space = p->owner();
   3357   DCHECK_NOT_NULL(space);
   3358   DCHECK(free_list_mode == IGNORE_FREE_LIST || space->identity() == OLD_SPACE ||
   3359          space->identity() == CODE_SPACE || space->identity() == MAP_SPACE);
   3360   DCHECK(!p->IsEvacuationCandidate() && !p->SweepingDone());
   3361 
   3362   // If there are old-to-new slots in that page, we have to filter out slots
   3363   // that are in dead memory which is freed by the sweeper.
   3364   ClearOldToNewSlotsMode slots_clearing_mode = GetClearOldToNewSlotsMode(p);
   3365 
   3366   // The free ranges map is used for filtering typed slots.
   3367   std::map<uint32_t, uint32_t> free_ranges;
   3368 
   3369   // Before we sweep objects on the page, we free dead array buffers which
   3370   // requires valid mark bits.
   3371   ArrayBufferTracker::FreeDead(p);
   3372 
   3373   Address free_start = p->area_start();
   3374   DCHECK(reinterpret_cast<intptr_t>(free_start) % (32 * kPointerSize) == 0);
   3375 
   3376   // If we use the skip list for code space pages, we have to lock the skip
   3377   // list because it could be accessed concurrently by the runtime or the
   3378   // deoptimizer.
   3379   const bool rebuild_skip_list =
   3380       space->identity() == CODE_SPACE && p->skip_list() != nullptr;
   3381   SkipList* skip_list = p->skip_list();
   3382   if (rebuild_skip_list) {
   3383     skip_list->Clear();
   3384   }
   3385 
   3386   intptr_t freed_bytes = 0;
   3387   intptr_t max_freed_bytes = 0;
   3388   int curr_region = -1;
   3389 
   3390   LiveObjectIterator<kBlackObjects> it(p);
   3391   HeapObject* object = NULL;
   3392 
   3393   while ((object = it.Next()) != NULL) {
   3394     DCHECK(ObjectMarking::IsBlack(object));
   3395     Address free_end = object->address();
   3396     if (free_end != free_start) {
   3397       CHECK_GT(free_end, free_start);
   3398       size_t size = static_cast<size_t>(free_end - free_start);
   3399       if (free_space_mode == ZAP_FREE_SPACE) {
   3400         memset(free_start, 0xcc, size);
   3401       }
   3402       if (free_list_mode == REBUILD_FREE_LIST) {
   3403         freed_bytes = reinterpret_cast<PagedSpace*>(space)->UnaccountedFree(
   3404             free_start, size);
   3405         max_freed_bytes = Max(freed_bytes, max_freed_bytes);
   3406       } else {
   3407         p->heap()->CreateFillerObjectAt(free_start, static_cast<int>(size),
   3408                                         ClearRecordedSlots::kNo);
   3409       }
   3410 
   3411       if (slots_clearing_mode == CLEAR_REGULAR_SLOTS) {
   3412         RememberedSet<OLD_TO_NEW>::RemoveRange(p, free_start, free_end,
   3413                                                SlotSet::KEEP_EMPTY_BUCKETS);
   3414       } else if (slots_clearing_mode == CLEAR_TYPED_SLOTS) {
   3415         free_ranges.insert(std::pair<uint32_t, uint32_t>(
   3416             static_cast<uint32_t>(free_start - p->address()),
   3417             static_cast<uint32_t>(free_end - p->address())));
   3418       }
   3419     }
   3420     Map* map = object->synchronized_map();
   3421     int size = object->SizeFromMap(map);
   3422     if (rebuild_skip_list) {
   3423       int new_region_start = SkipList::RegionNumber(free_end);
   3424       int new_region_end =
   3425           SkipList::RegionNumber(free_end + size - kPointerSize);
   3426       if (new_region_start != curr_region || new_region_end != curr_region) {
   3427         skip_list->AddObject(free_end, size);
   3428         curr_region = new_region_end;
   3429       }
   3430     }
   3431     free_start = free_end + size;
   3432   }
   3433 
   3434   if (free_start != p->area_end()) {
   3435     CHECK_GT(p->area_end(), free_start);
   3436     size_t size = static_cast<size_t>(p->area_end() - free_start);
   3437     if (free_space_mode == ZAP_FREE_SPACE) {
   3438       memset(free_start, 0xcc, size);
   3439     }
   3440     if (free_list_mode == REBUILD_FREE_LIST) {
   3441       freed_bytes = reinterpret_cast<PagedSpace*>(space)->UnaccountedFree(
   3442           free_start, size);
   3443       max_freed_bytes = Max(freed_bytes, max_freed_bytes);
   3444     } else {
   3445       p->heap()->CreateFillerObjectAt(free_start, static_cast<int>(size),
   3446                                       ClearRecordedSlots::kNo);
   3447     }
   3448 
   3449     if (slots_clearing_mode == CLEAR_REGULAR_SLOTS) {
   3450       RememberedSet<OLD_TO_NEW>::RemoveRange(p, free_start, p->area_end(),
   3451                                              SlotSet::KEEP_EMPTY_BUCKETS);
   3452     } else if (slots_clearing_mode == CLEAR_TYPED_SLOTS) {
   3453       free_ranges.insert(std::pair<uint32_t, uint32_t>(
   3454           static_cast<uint32_t>(free_start - p->address()),
   3455           static_cast<uint32_t>(p->area_end() - p->address())));
   3456     }
   3457   }
   3458 
   3459   // Clear invalid typed slots after collection all free ranges.
   3460   if (slots_clearing_mode == CLEAR_TYPED_SLOTS) {
   3461     p->typed_old_to_new_slots()->RemoveInvaldSlots(free_ranges);
   3462   }
   3463 
   3464   // Clear the mark bits of that page and reset live bytes count.
   3465   p->ClearLiveness();
   3466 
   3467   p->concurrent_sweeping_state().SetValue(Page::kSweepingDone);
   3468   if (free_list_mode == IGNORE_FREE_LIST) return 0;
   3469   return static_cast<int>(FreeList::GuaranteedAllocatable(max_freed_bytes));
   3470 }
   3471 
   3472 void MarkCompactCollector::InvalidateCode(Code* code) {
   3473   Page* page = Page::FromAddress(code->address());
   3474   Address start = code->instruction_start();
   3475   Address end = code->address() + code->Size();
   3476 
   3477   RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(page, start, end);
   3478 
   3479   if (heap_->incremental_marking()->IsCompacting() &&
   3480       !ShouldSkipEvacuationSlotRecording(code)) {
   3481     DCHECK(compacting_);
   3482 
   3483     // If the object is white than no slots were recorded on it yet.
   3484     if (ObjectMarking::IsWhite(code)) return;
   3485 
   3486     // Ignore all slots that might have been recorded in the body of the
   3487     // deoptimized code object. Assumption: no slots will be recorded for
   3488     // this object after invalidating it.
   3489     RememberedSet<OLD_TO_OLD>::RemoveRangeTyped(page, start, end);
   3490   }
   3491 }
   3492 
   3493 
   3494 // Return true if the given code is deoptimized or will be deoptimized.
   3495 bool MarkCompactCollector::WillBeDeoptimized(Code* code) {
   3496   return code->is_optimized_code() && code->marked_for_deoptimization();
   3497 }
   3498 
   3499 
   3500 #ifdef VERIFY_HEAP
   3501 static void VerifyAllBlackObjects(MemoryChunk* page) {
   3502   LiveObjectIterator<kAllLiveObjects> it(page);
   3503   HeapObject* object = NULL;
   3504   while ((object = it.Next()) != NULL) {
   3505     CHECK(ObjectMarking::IsBlack(object));
   3506   }
   3507 }
   3508 #endif  // VERIFY_HEAP
   3509 
   3510 void MarkCompactCollector::RecordLiveSlotsOnPage(Page* page) {
   3511   EvacuateRecordOnlyVisitor visitor(heap());
   3512   VisitLiveObjects(page, &visitor, kKeepMarking);
   3513 }
   3514 
   3515 template <class Visitor>
   3516 bool MarkCompactCollector::VisitLiveObjects(MemoryChunk* page, Visitor* visitor,
   3517                                             IterationMode mode) {
   3518 #ifdef VERIFY_HEAP
   3519   VerifyAllBlackObjects(page);
   3520 #endif  // VERIFY_HEAP
   3521 
   3522   LiveObjectIterator<kBlackObjects> it(page);
   3523   HeapObject* object = nullptr;
   3524   while ((object = it.Next()) != nullptr) {
   3525     DCHECK(ObjectMarking::IsBlack(object));
   3526     if (!visitor->Visit(object)) {
   3527       if (mode == kClearMarkbits) {
   3528         page->markbits()->ClearRange(
   3529             page->AddressToMarkbitIndex(page->area_start()),
   3530             page->AddressToMarkbitIndex(object->address()));
   3531         if (page->old_to_new_slots() != nullptr) {
   3532           page->old_to_new_slots()->RemoveRange(
   3533               0, static_cast<int>(object->address() - page->address()),
   3534               SlotSet::PREFREE_EMPTY_BUCKETS);
   3535         }
   3536         if (page->typed_old_to_new_slots() != nullptr) {
   3537           RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(page, page->address(),
   3538                                                       object->address());
   3539         }
   3540         RecomputeLiveBytes(page);
   3541       }
   3542       return false;
   3543     }
   3544   }
   3545   if (mode == kClearMarkbits) {
   3546     page->ClearLiveness();
   3547   }
   3548   return true;
   3549 }
   3550 
   3551 
   3552 void MarkCompactCollector::RecomputeLiveBytes(MemoryChunk* page) {
   3553   LiveObjectIterator<kBlackObjects> it(page);
   3554   int new_live_size = 0;
   3555   HeapObject* object = nullptr;
   3556   while ((object = it.Next()) != nullptr) {
   3557     new_live_size += object->Size();
   3558   }
   3559   page->SetLiveBytes(new_live_size);
   3560 }
   3561 
   3562 void MarkCompactCollector::Sweeper::AddSweptPageSafe(PagedSpace* space,
   3563                                                      Page* page) {
   3564   base::LockGuard<base::Mutex> guard(&mutex_);
   3565   swept_list_[space->identity()].Add(page);
   3566 }
   3567 
   3568 void MarkCompactCollector::EvacuateNewSpaceAndCandidates() {
   3569   TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE);
   3570   Heap::RelocationLock relocation_lock(heap());
   3571 
   3572   {
   3573     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_PROLOGUE);
   3574     EvacuatePrologue();
   3575   }
   3576 
   3577   {
   3578     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_COPY);
   3579     EvacuationScope evacuation_scope(this);
   3580     EvacuatePagesInParallel();
   3581   }
   3582 
   3583   UpdatePointersAfterEvacuation();
   3584 
   3585   {
   3586     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_REBALANCE);
   3587     if (!heap()->new_space()->Rebalance()) {
   3588       FatalProcessOutOfMemory("NewSpace::Rebalance");
   3589     }
   3590   }
   3591 
   3592   // Give pages that are queued to be freed back to the OS. Note that filtering
   3593   // slots only handles old space (for unboxed doubles), and thus map space can
   3594   // still contain stale pointers. We only free the chunks after pointer updates
   3595   // to still have access to page headers.
   3596   heap()->memory_allocator()->unmapper()->FreeQueuedChunks();
   3597 
   3598   {
   3599     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_CLEAN_UP);
   3600 
   3601     for (Page* p : new_space_evacuation_pages_) {
   3602       if (p->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION)) {
   3603         p->ClearFlag(Page::PAGE_NEW_NEW_PROMOTION);
   3604         sweeper().AddPage(p->owner()->identity(), p);
   3605       } else if (p->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION)) {
   3606         p->ClearFlag(Page::PAGE_NEW_OLD_PROMOTION);
   3607         p->ForAllFreeListCategories(
   3608             [](FreeListCategory* category) { DCHECK(!category->is_linked()); });
   3609         sweeper().AddPage(p->owner()->identity(), p);
   3610       }
   3611     }
   3612     new_space_evacuation_pages_.Rewind(0);
   3613 
   3614     for (Page* p : old_space_evacuation_pages_) {
   3615       // Important: skip list should be cleared only after roots were updated
   3616       // because root iteration traverses the stack and might have to find
   3617       // code objects from non-updated pc pointing into evacuation candidate.
   3618       SkipList* list = p->skip_list();
   3619       if (list != NULL) list->Clear();
   3620       if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) {
   3621         sweeper().AddPage(p->owner()->identity(), p);
   3622         p->ClearFlag(Page::COMPACTION_WAS_ABORTED);
   3623       }
   3624     }
   3625   }
   3626 
   3627   {
   3628     TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_EPILOGUE);
   3629     EvacuateEpilogue();
   3630   }
   3631 
   3632 #ifdef VERIFY_HEAP
   3633   if (FLAG_verify_heap && !sweeper().sweeping_in_progress()) {
   3634     VerifyEvacuation(heap());
   3635   }
   3636 #endif
   3637 }
   3638 
   3639 template <PointerDirection direction>
   3640 class PointerUpdateJobTraits {
   3641  public:
   3642   typedef int PerPageData;  // Per page data is not used in this job.
   3643   typedef int PerTaskData;  // Per task data is not used in this job.
   3644 
   3645   static bool ProcessPageInParallel(Heap* heap, PerTaskData, MemoryChunk* chunk,
   3646                                     PerPageData) {
   3647     UpdateUntypedPointers(heap, chunk);
   3648     UpdateTypedPointers(heap, chunk);
   3649     return true;
   3650   }
   3651   static const bool NeedSequentialFinalization = false;
   3652   static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) {
   3653   }
   3654 
   3655  private:
   3656   static void UpdateUntypedPointers(Heap* heap, MemoryChunk* chunk) {
   3657     if (direction == OLD_TO_NEW) {
   3658       RememberedSet<OLD_TO_NEW>::Iterate(chunk, [heap](Address slot) {
   3659         return CheckAndUpdateOldToNewSlot(heap, slot);
   3660       });
   3661     } else {
   3662       RememberedSet<OLD_TO_OLD>::Iterate(chunk, [](Address slot) {
   3663         return UpdateSlot(reinterpret_cast<Object**>(slot));
   3664       });
   3665     }
   3666   }
   3667 
   3668   static void UpdateTypedPointers(Heap* heap, MemoryChunk* chunk) {
   3669     if (direction == OLD_TO_OLD) {
   3670       Isolate* isolate = heap->isolate();
   3671       RememberedSet<OLD_TO_OLD>::IterateTyped(
   3672           chunk, [isolate](SlotType type, Address host_addr, Address slot) {
   3673             return UpdateTypedSlotHelper::UpdateTypedSlot(isolate, type, slot,
   3674                                                           UpdateSlot);
   3675           });
   3676     } else {
   3677       Isolate* isolate = heap->isolate();
   3678       RememberedSet<OLD_TO_NEW>::IterateTyped(
   3679           chunk,
   3680           [isolate, heap](SlotType type, Address host_addr, Address slot) {
   3681             return UpdateTypedSlotHelper::UpdateTypedSlot(
   3682                 isolate, type, slot, [heap](Object** slot) {
   3683                   return CheckAndUpdateOldToNewSlot(
   3684                       heap, reinterpret_cast<Address>(slot));
   3685                 });
   3686           });
   3687     }
   3688   }
   3689 
   3690   static SlotCallbackResult CheckAndUpdateOldToNewSlot(Heap* heap,
   3691                                                        Address slot_address) {
   3692     // There may be concurrent action on slots in dead objects. Concurrent
   3693     // sweeper threads may overwrite the slot content with a free space object.
   3694     // Moreover, the pointed-to object may also get concurrently overwritten
   3695     // with a free space object. The sweeper always gets priority performing
   3696     // these writes.
   3697     base::NoBarrierAtomicValue<Object*>* slot =
   3698         base::NoBarrierAtomicValue<Object*>::FromAddress(slot_address);
   3699     Object* slot_reference = slot->Value();
   3700     if (heap->InFromSpace(slot_reference)) {
   3701       HeapObject* heap_object = reinterpret_cast<HeapObject*>(slot_reference);
   3702       DCHECK(heap_object->IsHeapObject());
   3703       MapWord map_word = heap_object->map_word();
   3704       // There could still be stale pointers in large object space, map space,
   3705       // and old space for pages that have been promoted.
   3706       if (map_word.IsForwardingAddress()) {
   3707         // A sweeper thread may concurrently write a size value which looks like
   3708         // a forwarding pointer. We have to ignore these values.
   3709         if (map_word.ToRawValue() < Page::kPageSize) {
   3710           return REMOVE_SLOT;
   3711         }
   3712         // Update the corresponding slot only if the slot content did not
   3713         // change in the meantime. This may happen when a concurrent sweeper
   3714         // thread stored a free space object at that memory location.
   3715         slot->TrySetValue(slot_reference, map_word.ToForwardingAddress());
   3716       }
   3717       // If the object was in from space before and is after executing the
   3718       // callback in to space, the object is still live.
   3719       // Unfortunately, we do not know about the slot. It could be in a
   3720       // just freed free space object.
   3721       if (heap->InToSpace(slot->Value())) {
   3722         return KEEP_SLOT;
   3723       }
   3724     } else if (heap->InToSpace(slot_reference)) {
   3725       // Slots can point to "to" space if the page has been moved, or if the
   3726       // slot has been recorded multiple times in the remembered set. Since
   3727       // there is no forwarding information present we need to check the
   3728       // markbits to determine liveness.
   3729       if (ObjectMarking::IsBlack(reinterpret_cast<HeapObject*>(slot_reference)))
   3730         return KEEP_SLOT;
   3731     } else {
   3732       DCHECK(!heap->InNewSpace(slot_reference));
   3733     }
   3734     return REMOVE_SLOT;
   3735   }
   3736 };
   3737 
   3738 int NumberOfPointerUpdateTasks(int pages) {
   3739   if (!FLAG_parallel_pointer_update) return 1;
   3740   const int available_cores = Max(
   3741       1, static_cast<int>(
   3742              V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads()));
   3743   const int kPagesPerTask = 4;
   3744   return Min(available_cores, (pages + kPagesPerTask - 1) / kPagesPerTask);
   3745 }
   3746 
   3747 template <PointerDirection direction>
   3748 void UpdatePointersInParallel(Heap* heap, base::Semaphore* semaphore) {
   3749   PageParallelJob<PointerUpdateJobTraits<direction> > job(
   3750       heap, heap->isolate()->cancelable_task_manager(), semaphore);
   3751   RememberedSet<direction>::IterateMemoryChunks(
   3752       heap, [&job](MemoryChunk* chunk) { job.AddPage(chunk, 0); });
   3753   int num_pages = job.NumberOfPages();
   3754   int num_tasks = NumberOfPointerUpdateTasks(num_pages);
   3755   job.Run(num_tasks, [](int i) { return 0; });
   3756 }
   3757 
   3758 class ToSpacePointerUpdateJobTraits {
   3759  public:
   3760   typedef std::pair<Address, Address> PerPageData;
   3761   typedef PointersUpdatingVisitor* PerTaskData;
   3762 
   3763   static bool ProcessPageInParallel(Heap* heap, PerTaskData visitor,
   3764                                     MemoryChunk* chunk, PerPageData limits) {
   3765     if (chunk->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION)) {
   3766       // New->new promoted pages contain garbage so they require iteration
   3767       // using markbits.
   3768       ProcessPageInParallelVisitLive(heap, visitor, chunk, limits);
   3769     } else {
   3770       ProcessPageInParallelVisitAll(heap, visitor, chunk, limits);
   3771     }
   3772     return true;
   3773   }
   3774 
   3775   static const bool NeedSequentialFinalization = false;
   3776   static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) {
   3777   }
   3778 
   3779  private:
   3780   static void ProcessPageInParallelVisitAll(Heap* heap, PerTaskData visitor,
   3781                                             MemoryChunk* chunk,
   3782                                             PerPageData limits) {
   3783     for (Address cur = limits.first; cur < limits.second;) {
   3784       HeapObject* object = HeapObject::FromAddress(cur);
   3785       Map* map = object->map();
   3786       int size = object->SizeFromMap(map);
   3787       object->IterateBody(map->instance_type(), size, visitor);
   3788       cur += size;
   3789     }
   3790   }
   3791 
   3792   static void ProcessPageInParallelVisitLive(Heap* heap, PerTaskData visitor,
   3793                                              MemoryChunk* chunk,
   3794                                              PerPageData limits) {
   3795     LiveObjectIterator<kBlackObjects> it(chunk);
   3796     HeapObject* object = NULL;
   3797     while ((object = it.Next()) != NULL) {
   3798       Map* map = object->map();
   3799       int size = object->SizeFromMap(map);
   3800       object->IterateBody(map->instance_type(), size, visitor);
   3801     }
   3802   }
   3803 };
   3804 
   3805 void UpdateToSpacePointersInParallel(Heap* heap, base::Semaphore* semaphore) {
   3806   PageParallelJob<ToSpacePointerUpdateJobTraits> job(
   3807       heap, heap->isolate()->cancelable_task_manager(), semaphore);
   3808   Address space_start = heap->new_space()->bottom();
   3809   Address space_end = heap->new_space()->top();
   3810   for (Page* page : PageRange(space_start, space_end)) {
   3811     Address start =
   3812         page->Contains(space_start) ? space_start : page->area_start();
   3813     Address end = page->Contains(space_end) ? space_end : page->area_end();
   3814     job.AddPage(page, std::make_pair(start, end));
   3815   }
   3816   PointersUpdatingVisitor visitor;
   3817   int num_tasks = FLAG_parallel_pointer_update ? job.NumberOfPages() : 1;
   3818   job.Run(num_tasks, [&visitor](int i) { return &visitor; });
   3819 }
   3820 
   3821 void MarkCompactCollector::UpdatePointersAfterEvacuation() {
   3822   TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS);
   3823 
   3824   PointersUpdatingVisitor updating_visitor;
   3825 
   3826   {
   3827     TRACE_GC(heap()->tracer(),
   3828              GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_NEW);
   3829     UpdateToSpacePointersInParallel(heap_, &page_parallel_job_semaphore_);
   3830     // Update roots.
   3831     heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE);
   3832     UpdatePointersInParallel<OLD_TO_NEW>(heap_, &page_parallel_job_semaphore_);
   3833   }
   3834 
   3835   {
   3836     Heap* heap = this->heap();
   3837     TRACE_GC(heap->tracer(),
   3838              GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_EVACUATED);
   3839     UpdatePointersInParallel<OLD_TO_OLD>(heap_, &page_parallel_job_semaphore_);
   3840   }
   3841 
   3842   {
   3843     TRACE_GC(heap()->tracer(),
   3844              GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_WEAK);
   3845     // Update pointers from external string table.
   3846     heap_->UpdateReferencesInExternalStringTable(
   3847         &UpdateReferenceInExternalStringTableEntry);
   3848 
   3849     EvacuationWeakObjectRetainer evacuation_object_retainer;
   3850     heap()->ProcessWeakListRoots(&evacuation_object_retainer);
   3851   }
   3852 }
   3853 
   3854 
   3855 void MarkCompactCollector::ReleaseEvacuationCandidates() {
   3856   for (Page* p : old_space_evacuation_pages_) {
   3857     if (!p->IsEvacuationCandidate()) continue;
   3858     PagedSpace* space = static_cast<PagedSpace*>(p->owner());
   3859     p->ResetLiveBytes();
   3860     CHECK(p->SweepingDone());
   3861     space->ReleasePage(p);
   3862   }
   3863   old_space_evacuation_pages_.Rewind(0);
   3864   compacting_ = false;
   3865   heap()->memory_allocator()->unmapper()->FreeQueuedChunks();
   3866 }
   3867 
   3868 int MarkCompactCollector::Sweeper::ParallelSweepSpace(AllocationSpace identity,
   3869                                                       int required_freed_bytes,
   3870                                                       int max_pages) {
   3871   int max_freed = 0;
   3872   int pages_freed = 0;
   3873   Page* page = nullptr;
   3874   while ((page = GetSweepingPageSafe(identity)) != nullptr) {
   3875     int freed = ParallelSweepPage(page, identity);
   3876     pages_freed += 1;
   3877     DCHECK_GE(freed, 0);
   3878     max_freed = Max(max_freed, freed);
   3879     if ((required_freed_bytes) > 0 && (max_freed >= required_freed_bytes))
   3880       return max_freed;
   3881     if ((max_pages > 0) && (pages_freed >= max_pages)) return max_freed;
   3882   }
   3883   return max_freed;
   3884 }
   3885 
   3886 int MarkCompactCollector::Sweeper::ParallelSweepPage(Page* page,
   3887                                                      AllocationSpace identity) {
   3888   int max_freed = 0;
   3889   {
   3890     base::LockGuard<base::Mutex> guard(page->mutex());
   3891     // If this page was already swept in the meantime, we can return here.
   3892     if (page->SweepingDone()) return 0;
   3893     DCHECK_EQ(Page::kSweepingPending,
   3894               page->concurrent_sweeping_state().Value());
   3895     page->concurrent_sweeping_state().SetValue(Page::kSweepingInProgress);
   3896     const Sweeper::FreeSpaceTreatmentMode free_space_mode =
   3897         Heap::ShouldZapGarbage() ? ZAP_FREE_SPACE : IGNORE_FREE_SPACE;
   3898     if (identity == NEW_SPACE) {
   3899       RawSweep(page, IGNORE_FREE_LIST, free_space_mode);
   3900     } else {
   3901       max_freed = RawSweep(page, REBUILD_FREE_LIST, free_space_mode);
   3902     }
   3903     DCHECK(page->SweepingDone());
   3904 
   3905     // After finishing sweeping of a page we clean up its remembered set.
   3906     if (page->typed_old_to_new_slots()) {
   3907       page->typed_old_to_new_slots()->FreeToBeFreedChunks();
   3908     }
   3909     if (page->old_to_new_slots()) {
   3910       page->old_to_new_slots()->FreeToBeFreedBuckets();
   3911     }
   3912   }
   3913 
   3914   {
   3915     base::LockGuard<base::Mutex> guard(&mutex_);
   3916     swept_list_[identity].Add(page);
   3917   }
   3918   return max_freed;
   3919 }
   3920 
   3921 void MarkCompactCollector::Sweeper::AddPage(AllocationSpace space, Page* page) {
   3922   DCHECK(!FLAG_concurrent_sweeping || !AreSweeperTasksRunning());
   3923   PrepareToBeSweptPage(space, page);
   3924   sweeping_list_[space].push_back(page);
   3925 }
   3926 
   3927 void MarkCompactCollector::Sweeper::PrepareToBeSweptPage(AllocationSpace space,
   3928                                                          Page* page) {
   3929   page->concurrent_sweeping_state().SetValue(Page::kSweepingPending);
   3930   DCHECK_GE(page->area_size(), static_cast<size_t>(page->LiveBytes()));
   3931   size_t to_sweep = page->area_size() - page->LiveBytes();
   3932   if (space != NEW_SPACE)
   3933     heap_->paged_space(space)->accounting_stats_.ShrinkSpace(to_sweep);
   3934 }
   3935 
   3936 Page* MarkCompactCollector::Sweeper::GetSweepingPageSafe(
   3937     AllocationSpace space) {
   3938   base::LockGuard<base::Mutex> guard(&mutex_);
   3939   Page* page = nullptr;
   3940   if (!sweeping_list_[space].empty()) {
   3941     page = sweeping_list_[space].front();
   3942     sweeping_list_[space].pop_front();
   3943   }
   3944   return page;
   3945 }
   3946 
   3947 void MarkCompactCollector::Sweeper::AddSweepingPageSafe(AllocationSpace space,
   3948                                                         Page* page) {
   3949   base::LockGuard<base::Mutex> guard(&mutex_);
   3950   sweeping_list_[space].push_back(page);
   3951 }
   3952 
   3953 void MarkCompactCollector::StartSweepSpace(PagedSpace* space) {
   3954   space->ClearStats();
   3955 
   3956   int will_be_swept = 0;
   3957   bool unused_page_present = false;
   3958 
   3959   // Loop needs to support deletion if live bytes == 0 for a page.
   3960   for (auto it = space->begin(); it != space->end();) {
   3961     Page* p = *(it++);
   3962     DCHECK(p->SweepingDone());
   3963 
   3964     if (p->IsEvacuationCandidate()) {
   3965       // Will be processed in EvacuateNewSpaceAndCandidates.
   3966       DCHECK(evacuation_candidates_.length() > 0);
   3967       continue;
   3968     }
   3969 
   3970     if (p->IsFlagSet(Page::NEVER_ALLOCATE_ON_PAGE)) {
   3971       // We need to sweep the page to get it into an iterable state again. Note
   3972       // that this adds unusable memory into the free list that is later on
   3973       // (in the free list) dropped again. Since we only use the flag for
   3974       // testing this is fine.
   3975       p->concurrent_sweeping_state().SetValue(Page::kSweepingInProgress);
   3976       Sweeper::RawSweep(p, Sweeper::IGNORE_FREE_LIST,
   3977                         Heap::ShouldZapGarbage() ? Sweeper::ZAP_FREE_SPACE
   3978                                                  : Sweeper::IGNORE_FREE_SPACE);
   3979       continue;
   3980     }
   3981 
   3982     // One unused page is kept, all further are released before sweeping them.
   3983     if (p->LiveBytes() == 0) {
   3984       if (unused_page_present) {
   3985         if (FLAG_gc_verbose) {
   3986           PrintIsolate(isolate(), "sweeping: released page: %p",
   3987                        static_cast<void*>(p));
   3988         }
   3989         ArrayBufferTracker::FreeAll(p);
   3990         space->ReleasePage(p);
   3991         continue;
   3992       }
   3993       unused_page_present = true;
   3994     }
   3995 
   3996     sweeper().AddPage(space->identity(), p);
   3997     will_be_swept++;
   3998   }
   3999 
   4000   if (FLAG_gc_verbose) {
   4001     PrintIsolate(isolate(), "sweeping: space=%s initialized_for_sweeping=%d",
   4002                  AllocationSpaceName(space->identity()), will_be_swept);
   4003   }
   4004 }
   4005 
   4006 void MarkCompactCollector::StartSweepSpaces() {
   4007   TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_SWEEP);
   4008 #ifdef DEBUG
   4009   state_ = SWEEP_SPACES;
   4010 #endif
   4011 
   4012   {
   4013     {
   4014       GCTracer::Scope sweep_scope(heap()->tracer(),
   4015                                   GCTracer::Scope::MC_SWEEP_OLD);
   4016       StartSweepSpace(heap()->old_space());
   4017     }
   4018     {
   4019       GCTracer::Scope sweep_scope(heap()->tracer(),
   4020                                   GCTracer::Scope::MC_SWEEP_CODE);
   4021       StartSweepSpace(heap()->code_space());
   4022     }
   4023     {
   4024       GCTracer::Scope sweep_scope(heap()->tracer(),
   4025                                   GCTracer::Scope::MC_SWEEP_MAP);
   4026       StartSweepSpace(heap()->map_space());
   4027     }
   4028     sweeper().StartSweeping();
   4029   }
   4030 
   4031   // Deallocate unmarked large objects.
   4032   heap_->lo_space()->FreeUnmarkedObjects();
   4033 }
   4034 
   4035 Isolate* MarkCompactCollector::isolate() const { return heap_->isolate(); }
   4036 
   4037 
   4038 void MarkCompactCollector::Initialize() {
   4039   MarkCompactMarkingVisitor::Initialize();
   4040   IncrementalMarking::Initialize();
   4041 }
   4042 
   4043 void MarkCompactCollector::RecordCodeEntrySlot(HeapObject* host, Address slot,
   4044                                                Code* target) {
   4045   Page* target_page = Page::FromAddress(reinterpret_cast<Address>(target));
   4046   Page* source_page = Page::FromAddress(reinterpret_cast<Address>(host));
   4047   if (target_page->IsEvacuationCandidate() &&
   4048       !ShouldSkipEvacuationSlotRecording(host)) {
   4049     // TODO(ulan): remove this check after investigating crbug.com/414964.
   4050     CHECK(target->IsCode());
   4051     RememberedSet<OLD_TO_OLD>::InsertTyped(
   4052         source_page, reinterpret_cast<Address>(host), CODE_ENTRY_SLOT, slot);
   4053   }
   4054 }
   4055 
   4056 
   4057 void MarkCompactCollector::RecordCodeTargetPatch(Address pc, Code* target) {
   4058   DCHECK(heap()->gc_state() == Heap::MARK_COMPACT);
   4059   if (is_compacting()) {
   4060     Code* host =
   4061         isolate()->inner_pointer_to_code_cache()->GcSafeFindCodeForInnerPointer(
   4062             pc);
   4063     if (ObjectMarking::IsBlack(host)) {
   4064       RelocInfo rinfo(isolate(), pc, RelocInfo::CODE_TARGET, 0, host);
   4065       // The target is always in old space, we don't have to record the slot in
   4066       // the old-to-new remembered set.
   4067       DCHECK(!heap()->InNewSpace(target));
   4068       RecordRelocSlot(host, &rinfo, target);
   4069     }
   4070   }
   4071 }
   4072 
   4073 }  // namespace internal
   4074 }  // namespace v8
   4075