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 #ifndef V8_HEAP_MARK_COMPACT_H_
      6 #define V8_HEAP_MARK_COMPACT_H_
      7 
      8 #include <deque>
      9 
     10 #include "src/base/bits.h"
     11 #include "src/base/platform/condition-variable.h"
     12 #include "src/cancelable-task.h"
     13 #include "src/heap/marking.h"
     14 #include "src/heap/spaces.h"
     15 #include "src/heap/store-buffer.h"
     16 
     17 namespace v8 {
     18 namespace internal {
     19 
     20 // Callback function, returns whether an object is alive. The heap size
     21 // of the object is returned in size. It optionally updates the offset
     22 // to the first live object in the page (only used for old and map objects).
     23 typedef bool (*IsAliveFunction)(HeapObject* obj, int* size, int* offset);
     24 
     25 // Callback function to mark an object in a given heap.
     26 typedef void (*MarkObjectFunction)(Heap* heap, HeapObject* object);
     27 
     28 // Forward declarations.
     29 class CodeFlusher;
     30 class MarkCompactCollector;
     31 class MarkingVisitor;
     32 class RootMarkingVisitor;
     33 
     34 class ObjectMarking : public AllStatic {
     35  public:
     36   INLINE(static MarkBit MarkBitFrom(Address addr)) {
     37     MemoryChunk* p = MemoryChunk::FromAddress(addr);
     38     return p->markbits()->MarkBitFromIndex(p->AddressToMarkbitIndex(addr));
     39   }
     40 
     41   INLINE(static MarkBit MarkBitFrom(HeapObject* obj)) {
     42     return MarkBitFrom(reinterpret_cast<Address>(obj));
     43   }
     44 
     45   static Marking::ObjectColor Color(HeapObject* obj) {
     46     return Marking::Color(ObjectMarking::MarkBitFrom(obj));
     47   }
     48 
     49  private:
     50   DISALLOW_IMPLICIT_CONSTRUCTORS(ObjectMarking);
     51 };
     52 
     53 // ----------------------------------------------------------------------------
     54 // Marking deque for tracing live objects.
     55 class MarkingDeque {
     56  public:
     57   explicit MarkingDeque(Heap* heap)
     58       : backing_store_(nullptr),
     59         backing_store_committed_size_(0),
     60         array_(nullptr),
     61         top_(0),
     62         bottom_(0),
     63         mask_(0),
     64         overflowed_(false),
     65         in_use_(false),
     66         uncommit_task_pending_(false),
     67         heap_(heap) {}
     68 
     69   void SetUp();
     70   void TearDown();
     71 
     72   // Ensures that the marking deque is committed and will stay committed until
     73   // StopUsing() is called.
     74   void StartUsing();
     75   void StopUsing();
     76   void Clear();
     77 
     78   inline bool IsFull() { return ((top_ + 1) & mask_) == bottom_; }
     79 
     80   inline bool IsEmpty() { return top_ == bottom_; }
     81 
     82   bool overflowed() const { return overflowed_; }
     83 
     84   void ClearOverflowed() { overflowed_ = false; }
     85 
     86   void SetOverflowed() { overflowed_ = true; }
     87 
     88   // Push the object on the marking stack if there is room, otherwise mark the
     89   // deque as overflowed and wait for a rescan of the heap.
     90   INLINE(bool Push(HeapObject* object)) {
     91     DCHECK(object->IsHeapObject());
     92     if (IsFull()) {
     93       SetOverflowed();
     94       return false;
     95     } else {
     96       array_[top_] = object;
     97       top_ = ((top_ + 1) & mask_);
     98       return true;
     99     }
    100   }
    101 
    102   INLINE(HeapObject* Pop()) {
    103     DCHECK(!IsEmpty());
    104     top_ = ((top_ - 1) & mask_);
    105     HeapObject* object = array_[top_];
    106     DCHECK(object->IsHeapObject());
    107     return object;
    108   }
    109 
    110   // Unshift the object into the marking stack if there is room, otherwise mark
    111   // the deque as overflowed and wait for a rescan of the heap.
    112   INLINE(bool Unshift(HeapObject* object)) {
    113     DCHECK(object->IsHeapObject());
    114     if (IsFull()) {
    115       SetOverflowed();
    116       return false;
    117     } else {
    118       bottom_ = ((bottom_ - 1) & mask_);
    119       array_[bottom_] = object;
    120       return true;
    121     }
    122   }
    123 
    124   HeapObject** array() { return array_; }
    125   int bottom() { return bottom_; }
    126   int top() { return top_; }
    127   int mask() { return mask_; }
    128   void set_top(int top) { top_ = top; }
    129 
    130  private:
    131   // This task uncommits the marking_deque backing store if
    132   // markin_deque->in_use_ is false.
    133   class UncommitTask : public CancelableTask {
    134    public:
    135     explicit UncommitTask(Isolate* isolate, MarkingDeque* marking_deque)
    136         : CancelableTask(isolate), marking_deque_(marking_deque) {}
    137 
    138    private:
    139     // CancelableTask override.
    140     void RunInternal() override {
    141       base::LockGuard<base::Mutex> guard(&marking_deque_->mutex_);
    142       if (!marking_deque_->in_use_) {
    143         marking_deque_->Uncommit();
    144       }
    145       marking_deque_->uncommit_task_pending_ = false;
    146     }
    147 
    148     MarkingDeque* marking_deque_;
    149     DISALLOW_COPY_AND_ASSIGN(UncommitTask);
    150   };
    151 
    152   static const size_t kMaxSize = 4 * MB;
    153   static const size_t kMinSize = 256 * KB;
    154 
    155   // Must be called with mutex lock.
    156   void EnsureCommitted();
    157 
    158   // Must be called with mutex lock.
    159   void Uncommit();
    160 
    161   // Must be called with mutex lock.
    162   void StartUncommitTask();
    163 
    164   base::Mutex mutex_;
    165 
    166   base::VirtualMemory* backing_store_;
    167   size_t backing_store_committed_size_;
    168   HeapObject** array_;
    169   // array_[(top - 1) & mask_] is the top element in the deque.  The Deque is
    170   // empty when top_ == bottom_.  It is full when top_ + 1 == bottom
    171   // (mod mask + 1).
    172   int top_;
    173   int bottom_;
    174   int mask_;
    175   bool overflowed_;
    176   // in_use_ == true after taking mutex lock implies that the marking deque is
    177   // committed and will stay committed at least until in_use_ == false.
    178   bool in_use_;
    179   bool uncommit_task_pending_;
    180   Heap* heap_;
    181 
    182   DISALLOW_COPY_AND_ASSIGN(MarkingDeque);
    183 };
    184 
    185 
    186 // CodeFlusher collects candidates for code flushing during marking and
    187 // processes those candidates after marking has completed in order to
    188 // reset those functions referencing code objects that would otherwise
    189 // be unreachable. Code objects can be referenced in two ways:
    190 //    - SharedFunctionInfo references unoptimized code.
    191 //    - JSFunction references either unoptimized or optimized code.
    192 // We are not allowed to flush unoptimized code for functions that got
    193 // optimized or inlined into optimized code, because we might bailout
    194 // into the unoptimized code again during deoptimization.
    195 class CodeFlusher {
    196  public:
    197   explicit CodeFlusher(Isolate* isolate)
    198       : isolate_(isolate),
    199         jsfunction_candidates_head_(nullptr),
    200         shared_function_info_candidates_head_(nullptr) {}
    201 
    202   inline void AddCandidate(SharedFunctionInfo* shared_info);
    203   inline void AddCandidate(JSFunction* function);
    204 
    205   void EvictCandidate(SharedFunctionInfo* shared_info);
    206   void EvictCandidate(JSFunction* function);
    207 
    208   void ProcessCandidates() {
    209     ProcessSharedFunctionInfoCandidates();
    210     ProcessJSFunctionCandidates();
    211   }
    212 
    213   void IteratePointersToFromSpace(ObjectVisitor* v);
    214 
    215  private:
    216   void ProcessJSFunctionCandidates();
    217   void ProcessSharedFunctionInfoCandidates();
    218 
    219   static inline JSFunction** GetNextCandidateSlot(JSFunction* candidate);
    220   static inline JSFunction* GetNextCandidate(JSFunction* candidate);
    221   static inline void SetNextCandidate(JSFunction* candidate,
    222                                       JSFunction* next_candidate);
    223   static inline void ClearNextCandidate(JSFunction* candidate,
    224                                         Object* undefined);
    225 
    226   static inline SharedFunctionInfo* GetNextCandidate(
    227       SharedFunctionInfo* candidate);
    228   static inline void SetNextCandidate(SharedFunctionInfo* candidate,
    229                                       SharedFunctionInfo* next_candidate);
    230   static inline void ClearNextCandidate(SharedFunctionInfo* candidate);
    231 
    232   Isolate* isolate_;
    233   JSFunction* jsfunction_candidates_head_;
    234   SharedFunctionInfo* shared_function_info_candidates_head_;
    235 
    236   DISALLOW_COPY_AND_ASSIGN(CodeFlusher);
    237 };
    238 
    239 
    240 // Defined in isolate.h.
    241 class ThreadLocalTop;
    242 
    243 class MarkBitCellIterator BASE_EMBEDDED {
    244  public:
    245   explicit MarkBitCellIterator(MemoryChunk* chunk) : chunk_(chunk) {
    246     last_cell_index_ = Bitmap::IndexToCell(Bitmap::CellAlignIndex(
    247         chunk_->AddressToMarkbitIndex(chunk_->area_end())));
    248     cell_base_ = chunk_->area_start();
    249     cell_index_ = Bitmap::IndexToCell(
    250         Bitmap::CellAlignIndex(chunk_->AddressToMarkbitIndex(cell_base_)));
    251     cells_ = chunk_->markbits()->cells();
    252   }
    253 
    254   inline bool Done() { return cell_index_ == last_cell_index_; }
    255 
    256   inline bool HasNext() { return cell_index_ < last_cell_index_ - 1; }
    257 
    258   inline MarkBit::CellType* CurrentCell() {
    259     DCHECK(cell_index_ == Bitmap::IndexToCell(Bitmap::CellAlignIndex(
    260                               chunk_->AddressToMarkbitIndex(cell_base_))));
    261     return &cells_[cell_index_];
    262   }
    263 
    264   inline Address CurrentCellBase() {
    265     DCHECK(cell_index_ == Bitmap::IndexToCell(Bitmap::CellAlignIndex(
    266                               chunk_->AddressToMarkbitIndex(cell_base_))));
    267     return cell_base_;
    268   }
    269 
    270   inline void Advance() {
    271     cell_index_++;
    272     cell_base_ += Bitmap::kBitsPerCell * kPointerSize;
    273   }
    274 
    275   inline bool Advance(unsigned int new_cell_index) {
    276     if (new_cell_index != cell_index_) {
    277       DCHECK_GT(new_cell_index, cell_index_);
    278       DCHECK_LE(new_cell_index, last_cell_index_);
    279       unsigned int diff = new_cell_index - cell_index_;
    280       cell_index_ = new_cell_index;
    281       cell_base_ += diff * (Bitmap::kBitsPerCell * kPointerSize);
    282       return true;
    283     }
    284     return false;
    285   }
    286 
    287   // Return the next mark bit cell. If there is no next it returns 0;
    288   inline MarkBit::CellType PeekNext() {
    289     if (HasNext()) {
    290       return cells_[cell_index_ + 1];
    291     }
    292     return 0;
    293   }
    294 
    295  private:
    296   MemoryChunk* chunk_;
    297   MarkBit::CellType* cells_;
    298   unsigned int last_cell_index_;
    299   unsigned int cell_index_;
    300   Address cell_base_;
    301 };
    302 
    303 // Grey objects can happen on black pages when black objects transition to
    304 // grey e.g. when calling RecordWrites on them.
    305 enum LiveObjectIterationMode {
    306   kBlackObjects,
    307   kGreyObjects,
    308   kAllLiveObjects
    309 };
    310 
    311 template <LiveObjectIterationMode T>
    312 class LiveObjectIterator BASE_EMBEDDED {
    313  public:
    314   explicit LiveObjectIterator(MemoryChunk* chunk)
    315       : chunk_(chunk),
    316         it_(chunk_),
    317         cell_base_(it_.CurrentCellBase()),
    318         current_cell_(*it_.CurrentCell()) {
    319   }
    320 
    321   HeapObject* Next();
    322 
    323  private:
    324   inline Heap* heap() { return chunk_->heap(); }
    325 
    326   MemoryChunk* chunk_;
    327   MarkBitCellIterator it_;
    328   Address cell_base_;
    329   MarkBit::CellType current_cell_;
    330 };
    331 
    332 enum PageEvacuationMode { NEW_TO_NEW, NEW_TO_OLD };
    333 
    334 // -------------------------------------------------------------------------
    335 // Mark-Compact collector
    336 class MarkCompactCollector {
    337  public:
    338   class Evacuator;
    339 
    340   class Sweeper {
    341    public:
    342     class SweeperTask;
    343 
    344     enum FreeListRebuildingMode { REBUILD_FREE_LIST, IGNORE_FREE_LIST };
    345     enum FreeSpaceTreatmentMode { IGNORE_FREE_SPACE, ZAP_FREE_SPACE };
    346     enum ClearOldToNewSlotsMode {
    347       DO_NOT_CLEAR,
    348       CLEAR_REGULAR_SLOTS,
    349       CLEAR_TYPED_SLOTS
    350     };
    351 
    352     typedef std::deque<Page*> SweepingList;
    353     typedef List<Page*> SweptList;
    354 
    355     static int RawSweep(Page* p, FreeListRebuildingMode free_list_mode,
    356                         FreeSpaceTreatmentMode free_space_mode);
    357 
    358     explicit Sweeper(Heap* heap)
    359         : heap_(heap),
    360           pending_sweeper_tasks_semaphore_(0),
    361           sweeping_in_progress_(false),
    362           num_sweeping_tasks_(0) {}
    363 
    364     bool sweeping_in_progress() { return sweeping_in_progress_; }
    365 
    366     void AddPage(AllocationSpace space, Page* page);
    367 
    368     int ParallelSweepSpace(AllocationSpace identity, int required_freed_bytes,
    369                            int max_pages = 0);
    370     int ParallelSweepPage(Page* page, AllocationSpace identity);
    371 
    372     // After calling this function sweeping is considered to be in progress
    373     // and the main thread can sweep lazily, but the background sweeper tasks
    374     // are not running yet.
    375     void StartSweeping();
    376     void StartSweeperTasks();
    377     void EnsureCompleted();
    378     void EnsureNewSpaceCompleted();
    379     bool AreSweeperTasksRunning();
    380     bool IsSweepingCompleted(AllocationSpace space);
    381     void SweepOrWaitUntilSweepingCompleted(Page* page);
    382 
    383     void AddSweptPageSafe(PagedSpace* space, Page* page);
    384     Page* GetSweptPageSafe(PagedSpace* space);
    385 
    386    private:
    387     static const int kAllocationSpaces = LAST_PAGED_SPACE + 1;
    388 
    389     static ClearOldToNewSlotsMode GetClearOldToNewSlotsMode(Page* p);
    390 
    391     template <typename Callback>
    392     void ForAllSweepingSpaces(Callback callback) {
    393       for (int i = 0; i < kAllocationSpaces; i++) {
    394         callback(static_cast<AllocationSpace>(i));
    395       }
    396     }
    397 
    398     Page* GetSweepingPageSafe(AllocationSpace space);
    399     void AddSweepingPageSafe(AllocationSpace space, Page* page);
    400 
    401     void PrepareToBeSweptPage(AllocationSpace space, Page* page);
    402 
    403     Heap* heap_;
    404     base::Semaphore pending_sweeper_tasks_semaphore_;
    405     base::Mutex mutex_;
    406     SweptList swept_list_[kAllocationSpaces];
    407     SweepingList sweeping_list_[kAllocationSpaces];
    408     bool sweeping_in_progress_;
    409     base::AtomicNumber<intptr_t> num_sweeping_tasks_;
    410   };
    411 
    412   enum IterationMode {
    413     kKeepMarking,
    414     kClearMarkbits,
    415   };
    416 
    417   static void Initialize();
    418 
    419   void SetUp();
    420 
    421   void TearDown();
    422 
    423   void CollectEvacuationCandidates(PagedSpace* space);
    424 
    425   void AddEvacuationCandidate(Page* p);
    426 
    427   // Prepares for GC by resetting relocation info in old and map spaces and
    428   // choosing spaces to compact.
    429   void Prepare();
    430 
    431   // Performs a global garbage collection.
    432   void CollectGarbage();
    433 
    434   bool StartCompaction();
    435 
    436   void AbortCompaction();
    437 
    438 #ifdef DEBUG
    439   // Checks whether performing mark-compact collection.
    440   bool in_use() { return state_ > PREPARE_GC; }
    441   bool are_map_pointers_encoded() { return state_ == UPDATE_POINTERS; }
    442 #endif
    443 
    444   // Determine type of object and emit deletion log event.
    445   static void ReportDeleteIfNeeded(HeapObject* obj, Isolate* isolate);
    446 
    447   // Distinguishable invalid map encodings (for single word and multiple words)
    448   // that indicate free regions.
    449   static const uint32_t kSingleFreeEncoding = 0;
    450   static const uint32_t kMultiFreeEncoding = 1;
    451 
    452   static inline bool IsMarked(Object* obj);
    453   static bool IsUnmarkedHeapObjectWithHeap(Heap* heap, Object** p);
    454 
    455   inline Heap* heap() const { return heap_; }
    456   inline Isolate* isolate() const;
    457 
    458   CodeFlusher* code_flusher() { return code_flusher_; }
    459   inline bool is_code_flushing_enabled() const { return code_flusher_ != NULL; }
    460 
    461 #ifdef VERIFY_HEAP
    462   void VerifyValidStoreAndSlotsBufferEntries();
    463   void VerifyMarkbitsAreClean();
    464   static void VerifyMarkbitsAreClean(PagedSpace* space);
    465   static void VerifyMarkbitsAreClean(NewSpace* space);
    466   void VerifyWeakEmbeddedObjectsInCode();
    467   void VerifyOmittedMapChecks();
    468 #endif
    469 
    470   INLINE(static bool ShouldSkipEvacuationSlotRecording(Object* host)) {
    471     return Page::FromAddress(reinterpret_cast<Address>(host))
    472         ->ShouldSkipEvacuationSlotRecording();
    473   }
    474 
    475   static inline bool IsOnEvacuationCandidate(HeapObject* obj) {
    476     return Page::FromAddress(reinterpret_cast<Address>(obj))
    477         ->IsEvacuationCandidate();
    478   }
    479 
    480   void RecordRelocSlot(Code* host, RelocInfo* rinfo, Object* target);
    481   void RecordCodeEntrySlot(HeapObject* host, Address slot, Code* target);
    482   void RecordCodeTargetPatch(Address pc, Code* target);
    483   INLINE(void RecordSlot(HeapObject* object, Object** slot, Object* target));
    484   INLINE(void ForceRecordSlot(HeapObject* object, Object** slot,
    485                               Object* target));
    486 
    487   void UpdateSlots(SlotsBuffer* buffer);
    488   void UpdateSlotsRecordedIn(SlotsBuffer* buffer);
    489 
    490   void InvalidateCode(Code* code);
    491 
    492   void ClearMarkbits();
    493 
    494   bool is_compacting() const { return compacting_; }
    495 
    496   MarkingParity marking_parity() { return marking_parity_; }
    497 
    498   // Ensures that sweeping is finished.
    499   //
    500   // Note: Can only be called safely from main thread.
    501   void EnsureSweepingCompleted();
    502 
    503   // Help out in sweeping the corresponding space and refill memory that has
    504   // been regained.
    505   //
    506   // Note: Thread-safe.
    507   void SweepAndRefill(CompactionSpace* space);
    508 
    509   // Checks if sweeping is in progress right now on any space.
    510   bool sweeping_in_progress() { return sweeper().sweeping_in_progress(); }
    511 
    512   void set_evacuation(bool evacuation) { evacuation_ = evacuation; }
    513 
    514   bool evacuation() const { return evacuation_; }
    515 
    516   // Special case for processing weak references in a full collection. We need
    517   // to artificially keep AllocationSites alive for a time.
    518   void MarkAllocationSite(AllocationSite* site);
    519 
    520   // Mark objects in implicit references groups if their parent object
    521   // is marked.
    522   void MarkImplicitRefGroups(MarkObjectFunction mark_object);
    523 
    524   MarkingDeque* marking_deque() { return &marking_deque_; }
    525 
    526   Sweeper& sweeper() { return sweeper_; }
    527 
    528  private:
    529   template <PageEvacuationMode mode>
    530   class EvacuateNewSpacePageVisitor;
    531   class EvacuateNewSpaceVisitor;
    532   class EvacuateOldSpaceVisitor;
    533   class EvacuateRecordOnlyVisitor;
    534   class EvacuateVisitorBase;
    535   class HeapObjectVisitor;
    536   class ObjectStatsVisitor;
    537 
    538   explicit MarkCompactCollector(Heap* heap);
    539 
    540   bool WillBeDeoptimized(Code* code);
    541 
    542   void ComputeEvacuationHeuristics(size_t area_size,
    543                                    int* target_fragmentation_percent,
    544                                    size_t* max_evacuated_bytes);
    545 
    546   void VisitAllObjects(HeapObjectVisitor* visitor);
    547 
    548   void RecordObjectStats();
    549 
    550   // Finishes GC, performs heap verification if enabled.
    551   void Finish();
    552 
    553   // -----------------------------------------------------------------------
    554   // Phase 1: Marking live objects.
    555   //
    556   //  Before: The heap has been prepared for garbage collection by
    557   //          MarkCompactCollector::Prepare() and is otherwise in its
    558   //          normal state.
    559   //
    560   //   After: Live objects are marked and non-live objects are unmarked.
    561 
    562   friend class CodeMarkingVisitor;
    563   friend class IncrementalMarkingMarkingVisitor;
    564   friend class MarkCompactMarkingVisitor;
    565   friend class MarkingVisitor;
    566   friend class RecordMigratedSlotVisitor;
    567   friend class RootMarkingVisitor;
    568   friend class SharedFunctionInfoMarkingVisitor;
    569 
    570   // Mark code objects that are active on the stack to prevent them
    571   // from being flushed.
    572   void PrepareThreadForCodeFlushing(Isolate* isolate, ThreadLocalTop* top);
    573 
    574   void PrepareForCodeFlushing();
    575 
    576   // Marking operations for objects reachable from roots.
    577   void MarkLiveObjects();
    578 
    579   // Pushes a black object onto the marking stack and accounts for live bytes.
    580   // Note that this assumes live bytes have not yet been counted.
    581   INLINE(void PushBlack(HeapObject* obj));
    582 
    583   // Unshifts a black object into the marking stack and accounts for live bytes.
    584   // Note that this assumes lives bytes have already been counted.
    585   INLINE(void UnshiftBlack(HeapObject* obj));
    586 
    587   // Marks the object black and pushes it on the marking stack.
    588   // This is for non-incremental marking only.
    589   INLINE(void MarkObject(HeapObject* obj, MarkBit mark_bit));
    590 
    591   // Marks the object black assuming that it is not yet marked.
    592   // This is for non-incremental marking only.
    593   INLINE(void SetMark(HeapObject* obj, MarkBit mark_bit));
    594 
    595   // Mark the heap roots and all objects reachable from them.
    596   void MarkRoots(RootMarkingVisitor* visitor);
    597 
    598   // Mark the string table specially.  References to internalized strings from
    599   // the string table are weak.
    600   void MarkStringTable(RootMarkingVisitor* visitor);
    601 
    602   // Mark objects reachable (transitively) from objects in the marking stack
    603   // or overflowed in the heap.
    604   void ProcessMarkingDeque();
    605 
    606   // Mark objects reachable (transitively) from objects in the marking stack
    607   // or overflowed in the heap.  This respects references only considered in
    608   // the final atomic marking pause including the following:
    609   //    - Processing of objects reachable through Harmony WeakMaps.
    610   //    - Objects reachable due to host application logic like object groups,
    611   //      implicit references' groups, or embedder heap tracing.
    612   void ProcessEphemeralMarking(ObjectVisitor* visitor,
    613                                bool only_process_harmony_weak_collections);
    614 
    615   // If the call-site of the top optimized code was not prepared for
    616   // deoptimization, then treat the maps in the code as strong pointers,
    617   // otherwise a map can die and deoptimize the code.
    618   void ProcessTopOptimizedFrame(ObjectVisitor* visitor);
    619 
    620   // Collects a list of dependent code from maps embedded in optimize code.
    621   DependentCode* DependentCodeListFromNonLiveMaps();
    622 
    623   // Mark objects reachable (transitively) from objects in the marking
    624   // stack.  This function empties the marking stack, but may leave
    625   // overflowed objects in the heap, in which case the marking stack's
    626   // overflow flag will be set.
    627   void EmptyMarkingDeque();
    628 
    629   // Refill the marking stack with overflowed objects from the heap.  This
    630   // function either leaves the marking stack full or clears the overflow
    631   // flag on the marking stack.
    632   void RefillMarkingDeque();
    633 
    634   // Helper methods for refilling the marking stack by discovering grey objects
    635   // on various pages of the heap. Used by {RefillMarkingDeque} only.
    636   template <class T>
    637   void DiscoverGreyObjectsWithIterator(T* it);
    638   void DiscoverGreyObjectsOnPage(MemoryChunk* p);
    639   void DiscoverGreyObjectsInSpace(PagedSpace* space);
    640   void DiscoverGreyObjectsInNewSpace();
    641 
    642   // Callback function for telling whether the object *p is an unmarked
    643   // heap object.
    644   static bool IsUnmarkedHeapObject(Object** p);
    645 
    646   // Clear non-live references in weak cells, transition and descriptor arrays,
    647   // and deoptimize dependent code of non-live maps.
    648   void ClearNonLiveReferences();
    649   void MarkDependentCodeForDeoptimization(DependentCode* list);
    650   // Find non-live targets of simple transitions in the given list. Clear
    651   // transitions to non-live targets and if needed trim descriptors arrays.
    652   void ClearSimpleMapTransitions(Object* non_live_map_list);
    653   void ClearSimpleMapTransition(Map* map, Map* dead_transition);
    654   // Compact every array in the global list of transition arrays and
    655   // trim the corresponding descriptor array if a transition target is non-live.
    656   void ClearFullMapTransitions();
    657   bool CompactTransitionArray(Map* map, TransitionArray* transitions,
    658                               DescriptorArray* descriptors);
    659   void TrimDescriptorArray(Map* map, DescriptorArray* descriptors);
    660   void TrimEnumCache(Map* map, DescriptorArray* descriptors);
    661 
    662   // Mark all values associated with reachable keys in weak collections
    663   // encountered so far.  This might push new object or even new weak maps onto
    664   // the marking stack.
    665   void ProcessWeakCollections();
    666 
    667   // After all reachable objects have been marked those weak map entries
    668   // with an unreachable key are removed from all encountered weak maps.
    669   // The linked list of all encountered weak maps is destroyed.
    670   void ClearWeakCollections();
    671 
    672   // We have to remove all encountered weak maps from the list of weak
    673   // collections when incremental marking is aborted.
    674   void AbortWeakCollections();
    675 
    676   void ClearWeakCells(Object** non_live_map_list,
    677                       DependentCode** dependent_code_list);
    678   void AbortWeakCells();
    679 
    680   void AbortTransitionArrays();
    681 
    682   // Starts sweeping of spaces by contributing on the main thread and setting
    683   // up other pages for sweeping. Does not start sweeper tasks.
    684   void StartSweepSpaces();
    685   void StartSweepSpace(PagedSpace* space);
    686 
    687   void EvacuateNewSpacePrologue();
    688 
    689   void EvacuatePagesInParallel();
    690 
    691   // The number of parallel compaction tasks, including the main thread.
    692   int NumberOfParallelCompactionTasks(int pages, intptr_t live_bytes);
    693 
    694   void EvacuateNewSpaceAndCandidates();
    695 
    696   void UpdatePointersAfterEvacuation();
    697 
    698   // Iterates through all live objects on a page using marking information.
    699   // Returns whether all objects have successfully been visited.
    700   template <class Visitor>
    701   bool VisitLiveObjects(MemoryChunk* page, Visitor* visitor,
    702                         IterationMode mode);
    703 
    704   void RecomputeLiveBytes(MemoryChunk* page);
    705 
    706   void ReleaseEvacuationCandidates();
    707 
    708 
    709 #ifdef DEBUG
    710   friend class MarkObjectVisitor;
    711   static void VisitObject(HeapObject* obj);
    712 
    713   friend class UnmarkObjectVisitor;
    714   static void UnmarkObject(HeapObject* obj);
    715 #endif
    716 
    717   Heap* heap_;
    718 
    719   base::Semaphore page_parallel_job_semaphore_;
    720 
    721 #ifdef DEBUG
    722   enum CollectorState {
    723     IDLE,
    724     PREPARE_GC,
    725     MARK_LIVE_OBJECTS,
    726     SWEEP_SPACES,
    727     ENCODE_FORWARDING_ADDRESSES,
    728     UPDATE_POINTERS,
    729     RELOCATE_OBJECTS
    730   };
    731 
    732   // The current stage of the collector.
    733   CollectorState state_;
    734 #endif
    735 
    736   MarkingParity marking_parity_;
    737 
    738   bool was_marked_incrementally_;
    739 
    740   bool evacuation_;
    741 
    742   // True if we are collecting slots to perform evacuation from evacuation
    743   // candidates.
    744   bool compacting_;
    745 
    746   bool black_allocation_;
    747 
    748   bool have_code_to_deoptimize_;
    749 
    750   MarkingDeque marking_deque_;
    751 
    752   CodeFlusher* code_flusher_;
    753 
    754   List<Page*> evacuation_candidates_;
    755   List<Page*> newspace_evacuation_candidates_;
    756 
    757   Sweeper sweeper_;
    758 
    759   friend class Heap;
    760   friend class StoreBuffer;
    761 };
    762 
    763 
    764 class EvacuationScope BASE_EMBEDDED {
    765  public:
    766   explicit EvacuationScope(MarkCompactCollector* collector)
    767       : collector_(collector) {
    768     collector_->set_evacuation(true);
    769   }
    770 
    771   ~EvacuationScope() { collector_->set_evacuation(false); }
    772 
    773  private:
    774   MarkCompactCollector* collector_;
    775 };
    776 
    777 V8_EXPORT_PRIVATE const char* AllocationSpaceName(AllocationSpace space);
    778 }  // namespace internal
    779 }  // namespace v8
    780 
    781 #endif  // V8_HEAP_MARK_COMPACT_H_
    782