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