1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_MARK_COMPACT_H_ 29 #define V8_MARK_COMPACT_H_ 30 31 #include "compiler-intrinsics.h" 32 #include "spaces.h" 33 34 namespace v8 { 35 namespace internal { 36 37 // Callback function, returns whether an object is alive. The heap size 38 // of the object is returned in size. It optionally updates the offset 39 // to the first live object in the page (only used for old and map objects). 40 typedef bool (*IsAliveFunction)(HeapObject* obj, int* size, int* offset); 41 42 // Forward declarations. 43 class CodeFlusher; 44 class GCTracer; 45 class MarkCompactCollector; 46 class MarkingVisitor; 47 class RootMarkingVisitor; 48 49 50 class Marking { 51 public: 52 explicit Marking(Heap* heap) 53 : heap_(heap) { 54 } 55 56 INLINE(static MarkBit MarkBitFrom(Address addr)); 57 58 INLINE(static MarkBit MarkBitFrom(HeapObject* obj)) { 59 return MarkBitFrom(reinterpret_cast<Address>(obj)); 60 } 61 62 // Impossible markbits: 01 63 static const char* kImpossibleBitPattern; 64 INLINE(static bool IsImpossible(MarkBit mark_bit)) { 65 return !mark_bit.Get() && mark_bit.Next().Get(); 66 } 67 68 // Black markbits: 10 - this is required by the sweeper. 69 static const char* kBlackBitPattern; 70 INLINE(static bool IsBlack(MarkBit mark_bit)) { 71 return mark_bit.Get() && !mark_bit.Next().Get(); 72 } 73 74 // White markbits: 00 - this is required by the mark bit clearer. 75 static const char* kWhiteBitPattern; 76 INLINE(static bool IsWhite(MarkBit mark_bit)) { 77 return !mark_bit.Get(); 78 } 79 80 // Grey markbits: 11 81 static const char* kGreyBitPattern; 82 INLINE(static bool IsGrey(MarkBit mark_bit)) { 83 return mark_bit.Get() && mark_bit.Next().Get(); 84 } 85 86 INLINE(static void MarkBlack(MarkBit mark_bit)) { 87 mark_bit.Set(); 88 mark_bit.Next().Clear(); 89 } 90 91 INLINE(static void BlackToGrey(MarkBit markbit)) { 92 markbit.Next().Set(); 93 } 94 95 INLINE(static void WhiteToGrey(MarkBit markbit)) { 96 markbit.Set(); 97 markbit.Next().Set(); 98 } 99 100 INLINE(static void GreyToBlack(MarkBit markbit)) { 101 markbit.Next().Clear(); 102 } 103 104 INLINE(static void BlackToGrey(HeapObject* obj)) { 105 BlackToGrey(MarkBitFrom(obj)); 106 } 107 108 INLINE(static void AnyToGrey(MarkBit markbit)) { 109 markbit.Set(); 110 markbit.Next().Set(); 111 } 112 113 // Returns true if the the object whose mark is transferred is marked black. 114 bool TransferMark(Address old_start, Address new_start); 115 116 #ifdef DEBUG 117 enum ObjectColor { 118 BLACK_OBJECT, 119 WHITE_OBJECT, 120 GREY_OBJECT, 121 IMPOSSIBLE_COLOR 122 }; 123 124 static const char* ColorName(ObjectColor color) { 125 switch (color) { 126 case BLACK_OBJECT: return "black"; 127 case WHITE_OBJECT: return "white"; 128 case GREY_OBJECT: return "grey"; 129 case IMPOSSIBLE_COLOR: return "impossible"; 130 } 131 return "error"; 132 } 133 134 static ObjectColor Color(HeapObject* obj) { 135 return Color(Marking::MarkBitFrom(obj)); 136 } 137 138 static ObjectColor Color(MarkBit mark_bit) { 139 if (IsBlack(mark_bit)) return BLACK_OBJECT; 140 if (IsWhite(mark_bit)) return WHITE_OBJECT; 141 if (IsGrey(mark_bit)) return GREY_OBJECT; 142 UNREACHABLE(); 143 return IMPOSSIBLE_COLOR; 144 } 145 #endif 146 147 // Returns true if the transferred color is black. 148 INLINE(static bool TransferColor(HeapObject* from, 149 HeapObject* to)) { 150 MarkBit from_mark_bit = MarkBitFrom(from); 151 MarkBit to_mark_bit = MarkBitFrom(to); 152 bool is_black = false; 153 if (from_mark_bit.Get()) { 154 to_mark_bit.Set(); 155 is_black = true; // Looks black so far. 156 } 157 if (from_mark_bit.Next().Get()) { 158 to_mark_bit.Next().Set(); 159 is_black = false; // Was actually gray. 160 } 161 return is_black; 162 } 163 164 private: 165 Heap* heap_; 166 }; 167 168 // ---------------------------------------------------------------------------- 169 // Marking deque for tracing live objects. 170 class MarkingDeque { 171 public: 172 MarkingDeque() 173 : array_(NULL), top_(0), bottom_(0), mask_(0), overflowed_(false) { } 174 175 void Initialize(Address low, Address high) { 176 HeapObject** obj_low = reinterpret_cast<HeapObject**>(low); 177 HeapObject** obj_high = reinterpret_cast<HeapObject**>(high); 178 array_ = obj_low; 179 mask_ = RoundDownToPowerOf2(static_cast<int>(obj_high - obj_low)) - 1; 180 top_ = bottom_ = 0; 181 overflowed_ = false; 182 } 183 184 inline bool IsFull() { return ((top_ + 1) & mask_) == bottom_; } 185 186 inline bool IsEmpty() { return top_ == bottom_; } 187 188 bool overflowed() const { return overflowed_; } 189 190 void ClearOverflowed() { overflowed_ = false; } 191 192 void SetOverflowed() { overflowed_ = true; } 193 194 // Push the (marked) object on the marking stack if there is room, 195 // otherwise mark the object as overflowed and wait for a rescan of the 196 // heap. 197 INLINE(void PushBlack(HeapObject* object)) { 198 ASSERT(object->IsHeapObject()); 199 if (IsFull()) { 200 Marking::BlackToGrey(object); 201 MemoryChunk::IncrementLiveBytesFromGC(object->address(), -object->Size()); 202 SetOverflowed(); 203 } else { 204 array_[top_] = object; 205 top_ = ((top_ + 1) & mask_); 206 } 207 } 208 209 INLINE(void PushGrey(HeapObject* object)) { 210 ASSERT(object->IsHeapObject()); 211 if (IsFull()) { 212 SetOverflowed(); 213 } else { 214 array_[top_] = object; 215 top_ = ((top_ + 1) & mask_); 216 } 217 } 218 219 INLINE(HeapObject* Pop()) { 220 ASSERT(!IsEmpty()); 221 top_ = ((top_ - 1) & mask_); 222 HeapObject* object = array_[top_]; 223 ASSERT(object->IsHeapObject()); 224 return object; 225 } 226 227 INLINE(void UnshiftGrey(HeapObject* object)) { 228 ASSERT(object->IsHeapObject()); 229 if (IsFull()) { 230 SetOverflowed(); 231 } else { 232 bottom_ = ((bottom_ - 1) & mask_); 233 array_[bottom_] = object; 234 } 235 } 236 237 HeapObject** array() { return array_; } 238 int bottom() { return bottom_; } 239 int top() { return top_; } 240 int mask() { return mask_; } 241 void set_top(int top) { top_ = top; } 242 243 private: 244 HeapObject** array_; 245 // array_[(top - 1) & mask_] is the top element in the deque. The Deque is 246 // empty when top_ == bottom_. It is full when top_ + 1 == bottom 247 // (mod mask + 1). 248 int top_; 249 int bottom_; 250 int mask_; 251 bool overflowed_; 252 253 DISALLOW_COPY_AND_ASSIGN(MarkingDeque); 254 }; 255 256 257 class SlotsBufferAllocator { 258 public: 259 SlotsBuffer* AllocateBuffer(SlotsBuffer* next_buffer); 260 void DeallocateBuffer(SlotsBuffer* buffer); 261 262 void DeallocateChain(SlotsBuffer** buffer_address); 263 }; 264 265 266 // SlotsBuffer records a sequence of slots that has to be updated 267 // after live objects were relocated from evacuation candidates. 268 // All slots are either untyped or typed: 269 // - Untyped slots are expected to contain a tagged object pointer. 270 // They are recorded by an address. 271 // - Typed slots are expected to contain an encoded pointer to a heap 272 // object where the way of encoding depends on the type of the slot. 273 // They are recorded as a pair (SlotType, slot address). 274 // We assume that zero-page is never mapped this allows us to distinguish 275 // untyped slots from typed slots during iteration by a simple comparison: 276 // if element of slots buffer is less than NUMBER_OF_SLOT_TYPES then it 277 // is the first element of typed slot's pair. 278 class SlotsBuffer { 279 public: 280 typedef Object** ObjectSlot; 281 282 explicit SlotsBuffer(SlotsBuffer* next_buffer) 283 : idx_(0), chain_length_(1), next_(next_buffer) { 284 if (next_ != NULL) { 285 chain_length_ = next_->chain_length_ + 1; 286 } 287 } 288 289 ~SlotsBuffer() { 290 } 291 292 void Add(ObjectSlot slot) { 293 ASSERT(0 <= idx_ && idx_ < kNumberOfElements); 294 slots_[idx_++] = slot; 295 } 296 297 enum SlotType { 298 EMBEDDED_OBJECT_SLOT, 299 RELOCATED_CODE_OBJECT, 300 CODE_TARGET_SLOT, 301 CODE_ENTRY_SLOT, 302 DEBUG_TARGET_SLOT, 303 JS_RETURN_SLOT, 304 NUMBER_OF_SLOT_TYPES 305 }; 306 307 static const char* SlotTypeToString(SlotType type) { 308 switch (type) { 309 case EMBEDDED_OBJECT_SLOT: 310 return "EMBEDDED_OBJECT_SLOT"; 311 case RELOCATED_CODE_OBJECT: 312 return "RELOCATED_CODE_OBJECT"; 313 case CODE_TARGET_SLOT: 314 return "CODE_TARGET_SLOT"; 315 case CODE_ENTRY_SLOT: 316 return "CODE_ENTRY_SLOT"; 317 case DEBUG_TARGET_SLOT: 318 return "DEBUG_TARGET_SLOT"; 319 case JS_RETURN_SLOT: 320 return "JS_RETURN_SLOT"; 321 case NUMBER_OF_SLOT_TYPES: 322 return "NUMBER_OF_SLOT_TYPES"; 323 } 324 return "UNKNOWN SlotType"; 325 } 326 327 void UpdateSlots(Heap* heap); 328 329 void UpdateSlotsWithFilter(Heap* heap); 330 331 SlotsBuffer* next() { return next_; } 332 333 static int SizeOfChain(SlotsBuffer* buffer) { 334 if (buffer == NULL) return 0; 335 return static_cast<int>(buffer->idx_ + 336 (buffer->chain_length_ - 1) * kNumberOfElements); 337 } 338 339 inline bool IsFull() { 340 return idx_ == kNumberOfElements; 341 } 342 343 inline bool HasSpaceForTypedSlot() { 344 return idx_ < kNumberOfElements - 1; 345 } 346 347 static void UpdateSlotsRecordedIn(Heap* heap, 348 SlotsBuffer* buffer, 349 bool code_slots_filtering_required) { 350 while (buffer != NULL) { 351 if (code_slots_filtering_required) { 352 buffer->UpdateSlotsWithFilter(heap); 353 } else { 354 buffer->UpdateSlots(heap); 355 } 356 buffer = buffer->next(); 357 } 358 } 359 360 enum AdditionMode { 361 FAIL_ON_OVERFLOW, 362 IGNORE_OVERFLOW 363 }; 364 365 static bool ChainLengthThresholdReached(SlotsBuffer* buffer) { 366 return buffer != NULL && buffer->chain_length_ >= kChainLengthThreshold; 367 } 368 369 INLINE(static bool AddTo(SlotsBufferAllocator* allocator, 370 SlotsBuffer** buffer_address, 371 ObjectSlot slot, 372 AdditionMode mode)) { 373 SlotsBuffer* buffer = *buffer_address; 374 if (buffer == NULL || buffer->IsFull()) { 375 if (mode == FAIL_ON_OVERFLOW && ChainLengthThresholdReached(buffer)) { 376 allocator->DeallocateChain(buffer_address); 377 return false; 378 } 379 buffer = allocator->AllocateBuffer(buffer); 380 *buffer_address = buffer; 381 } 382 buffer->Add(slot); 383 return true; 384 } 385 386 static bool IsTypedSlot(ObjectSlot slot); 387 388 static bool AddTo(SlotsBufferAllocator* allocator, 389 SlotsBuffer** buffer_address, 390 SlotType type, 391 Address addr, 392 AdditionMode mode); 393 394 static const int kNumberOfElements = 1021; 395 396 private: 397 static const int kChainLengthThreshold = 15; 398 399 intptr_t idx_; 400 intptr_t chain_length_; 401 SlotsBuffer* next_; 402 ObjectSlot slots_[kNumberOfElements]; 403 }; 404 405 406 // CodeFlusher collects candidates for code flushing during marking and 407 // processes those candidates after marking has completed in order to 408 // reset those functions referencing code objects that would otherwise 409 // be unreachable. Code objects can be referenced in three ways: 410 // - SharedFunctionInfo references unoptimized code. 411 // - JSFunction references either unoptimized or optimized code. 412 // - OptimizedCodeMap references optimized code. 413 // We are not allowed to flush unoptimized code for functions that got 414 // optimized or inlined into optimized code, because we might bailout 415 // into the unoptimized code again during deoptimization. 416 class CodeFlusher { 417 public: 418 explicit CodeFlusher(Isolate* isolate) 419 : isolate_(isolate), 420 jsfunction_candidates_head_(NULL), 421 shared_function_info_candidates_head_(NULL), 422 optimized_code_map_holder_head_(NULL) {} 423 424 void AddCandidate(SharedFunctionInfo* shared_info) { 425 if (GetNextCandidate(shared_info) == NULL) { 426 SetNextCandidate(shared_info, shared_function_info_candidates_head_); 427 shared_function_info_candidates_head_ = shared_info; 428 } 429 } 430 431 void AddCandidate(JSFunction* function) { 432 ASSERT(function->code() == function->shared()->code()); 433 if (GetNextCandidate(function)->IsUndefined()) { 434 SetNextCandidate(function, jsfunction_candidates_head_); 435 jsfunction_candidates_head_ = function; 436 } 437 } 438 439 void AddOptimizedCodeMap(SharedFunctionInfo* code_map_holder) { 440 if (GetNextCodeMap(code_map_holder)->IsUndefined()) { 441 SetNextCodeMap(code_map_holder, optimized_code_map_holder_head_); 442 optimized_code_map_holder_head_ = code_map_holder; 443 } 444 } 445 446 void EvictOptimizedCodeMap(SharedFunctionInfo* code_map_holder); 447 void EvictCandidate(SharedFunctionInfo* shared_info); 448 void EvictCandidate(JSFunction* function); 449 450 void ProcessCandidates() { 451 ProcessOptimizedCodeMaps(); 452 ProcessSharedFunctionInfoCandidates(); 453 ProcessJSFunctionCandidates(); 454 } 455 456 void EvictAllCandidates() { 457 EvictOptimizedCodeMaps(); 458 EvictJSFunctionCandidates(); 459 EvictSharedFunctionInfoCandidates(); 460 } 461 462 void IteratePointersToFromSpace(ObjectVisitor* v); 463 464 private: 465 void ProcessOptimizedCodeMaps(); 466 void ProcessJSFunctionCandidates(); 467 void ProcessSharedFunctionInfoCandidates(); 468 void EvictOptimizedCodeMaps(); 469 void EvictJSFunctionCandidates(); 470 void EvictSharedFunctionInfoCandidates(); 471 472 static JSFunction** GetNextCandidateSlot(JSFunction* candidate) { 473 return reinterpret_cast<JSFunction**>( 474 HeapObject::RawField(candidate, JSFunction::kNextFunctionLinkOffset)); 475 } 476 477 static JSFunction* GetNextCandidate(JSFunction* candidate) { 478 Object* next_candidate = candidate->next_function_link(); 479 return reinterpret_cast<JSFunction*>(next_candidate); 480 } 481 482 static void SetNextCandidate(JSFunction* candidate, 483 JSFunction* next_candidate) { 484 candidate->set_next_function_link(next_candidate); 485 } 486 487 static void ClearNextCandidate(JSFunction* candidate, Object* undefined) { 488 ASSERT(undefined->IsUndefined()); 489 candidate->set_next_function_link(undefined, SKIP_WRITE_BARRIER); 490 } 491 492 static SharedFunctionInfo* GetNextCandidate(SharedFunctionInfo* candidate) { 493 Object* next_candidate = candidate->code()->gc_metadata(); 494 return reinterpret_cast<SharedFunctionInfo*>(next_candidate); 495 } 496 497 static void SetNextCandidate(SharedFunctionInfo* candidate, 498 SharedFunctionInfo* next_candidate) { 499 candidate->code()->set_gc_metadata(next_candidate); 500 } 501 502 static void ClearNextCandidate(SharedFunctionInfo* candidate) { 503 candidate->code()->set_gc_metadata(NULL, SKIP_WRITE_BARRIER); 504 } 505 506 static SharedFunctionInfo* GetNextCodeMap(SharedFunctionInfo* holder) { 507 FixedArray* code_map = FixedArray::cast(holder->optimized_code_map()); 508 Object* next_map = code_map->get(SharedFunctionInfo::kNextMapIndex); 509 return reinterpret_cast<SharedFunctionInfo*>(next_map); 510 } 511 512 static void SetNextCodeMap(SharedFunctionInfo* holder, 513 SharedFunctionInfo* next_holder) { 514 FixedArray* code_map = FixedArray::cast(holder->optimized_code_map()); 515 code_map->set(SharedFunctionInfo::kNextMapIndex, next_holder); 516 } 517 518 static void ClearNextCodeMap(SharedFunctionInfo* holder) { 519 FixedArray* code_map = FixedArray::cast(holder->optimized_code_map()); 520 code_map->set_undefined(SharedFunctionInfo::kNextMapIndex); 521 } 522 523 Isolate* isolate_; 524 JSFunction* jsfunction_candidates_head_; 525 SharedFunctionInfo* shared_function_info_candidates_head_; 526 SharedFunctionInfo* optimized_code_map_holder_head_; 527 528 DISALLOW_COPY_AND_ASSIGN(CodeFlusher); 529 }; 530 531 532 // Defined in isolate.h. 533 class ThreadLocalTop; 534 535 536 // ------------------------------------------------------------------------- 537 // Mark-Compact collector 538 class MarkCompactCollector { 539 public: 540 // Type of functions to compute forwarding addresses of objects in 541 // compacted spaces. Given an object and its size, return a (non-failure) 542 // Object* that will be the object after forwarding. There is a separate 543 // allocation function for each (compactable) space based on the location 544 // of the object before compaction. 545 typedef MaybeObject* (*AllocationFunction)(Heap* heap, 546 HeapObject* object, 547 int object_size); 548 549 // Type of functions to encode the forwarding address for an object. 550 // Given the object, its size, and the new (non-failure) object it will be 551 // forwarded to, encode the forwarding address. For paged spaces, the 552 // 'offset' input/output parameter contains the offset of the forwarded 553 // object from the forwarding address of the previous live object in the 554 // page as input, and is updated to contain the offset to be used for the 555 // next live object in the same page. For spaces using a different 556 // encoding (i.e., contiguous spaces), the offset parameter is ignored. 557 typedef void (*EncodingFunction)(Heap* heap, 558 HeapObject* old_object, 559 int object_size, 560 Object* new_object, 561 int* offset); 562 563 // Type of functions to process non-live objects. 564 typedef void (*ProcessNonLiveFunction)(HeapObject* object, Isolate* isolate); 565 566 // Pointer to member function, used in IterateLiveObjects. 567 typedef int (MarkCompactCollector::*LiveObjectCallback)(HeapObject* obj); 568 569 // Set the global flags, it must be called before Prepare to take effect. 570 inline void SetFlags(int flags); 571 572 static void Initialize(); 573 574 void TearDown(); 575 576 void CollectEvacuationCandidates(PagedSpace* space); 577 578 void AddEvacuationCandidate(Page* p); 579 580 // Prepares for GC by resetting relocation info in old and map spaces and 581 // choosing spaces to compact. 582 void Prepare(GCTracer* tracer); 583 584 // Performs a global garbage collection. 585 void CollectGarbage(); 586 587 enum CompactionMode { 588 INCREMENTAL_COMPACTION, 589 NON_INCREMENTAL_COMPACTION 590 }; 591 592 bool StartCompaction(CompactionMode mode); 593 594 void AbortCompaction(); 595 596 // During a full GC, there is a stack-allocated GCTracer that is used for 597 // bookkeeping information. Return a pointer to that tracer. 598 GCTracer* tracer() { return tracer_; } 599 600 #ifdef DEBUG 601 // Checks whether performing mark-compact collection. 602 bool in_use() { return state_ > PREPARE_GC; } 603 bool are_map_pointers_encoded() { return state_ == UPDATE_POINTERS; } 604 #endif 605 606 // Determine type of object and emit deletion log event. 607 static void ReportDeleteIfNeeded(HeapObject* obj, Isolate* isolate); 608 609 // Distinguishable invalid map encodings (for single word and multiple words) 610 // that indicate free regions. 611 static const uint32_t kSingleFreeEncoding = 0; 612 static const uint32_t kMultiFreeEncoding = 1; 613 614 static inline bool IsMarked(Object* obj); 615 616 inline Heap* heap() const { return heap_; } 617 inline Isolate* isolate() const; 618 619 CodeFlusher* code_flusher() { return code_flusher_; } 620 inline bool is_code_flushing_enabled() const { return code_flusher_ != NULL; } 621 void EnableCodeFlushing(bool enable); 622 623 enum SweeperType { 624 CONSERVATIVE, 625 LAZY_CONSERVATIVE, 626 PARALLEL_CONSERVATIVE, 627 CONCURRENT_CONSERVATIVE, 628 PRECISE 629 }; 630 631 enum SweepingParallelism { 632 SWEEP_SEQUENTIALLY, 633 SWEEP_IN_PARALLEL 634 }; 635 636 #ifdef VERIFY_HEAP 637 void VerifyMarkbitsAreClean(); 638 static void VerifyMarkbitsAreClean(PagedSpace* space); 639 static void VerifyMarkbitsAreClean(NewSpace* space); 640 void VerifyWeakEmbeddedObjectsInOptimizedCode(); 641 void VerifyOmittedMapChecks(); 642 #endif 643 644 // Sweep a single page from the given space conservatively. 645 // Return a number of reclaimed bytes. 646 template<SweepingParallelism type> 647 static intptr_t SweepConservatively(PagedSpace* space, 648 FreeList* free_list, 649 Page* p); 650 651 INLINE(static bool ShouldSkipEvacuationSlotRecording(Object** anchor)) { 652 return Page::FromAddress(reinterpret_cast<Address>(anchor))-> 653 ShouldSkipEvacuationSlotRecording(); 654 } 655 656 INLINE(static bool ShouldSkipEvacuationSlotRecording(Object* host)) { 657 return Page::FromAddress(reinterpret_cast<Address>(host))-> 658 ShouldSkipEvacuationSlotRecording(); 659 } 660 661 INLINE(static bool IsOnEvacuationCandidate(Object* obj)) { 662 return Page::FromAddress(reinterpret_cast<Address>(obj))-> 663 IsEvacuationCandidate(); 664 } 665 666 INLINE(void EvictEvacuationCandidate(Page* page)) { 667 if (FLAG_trace_fragmentation) { 668 PrintF("Page %p is too popular. Disabling evacuation.\n", 669 reinterpret_cast<void*>(page)); 670 } 671 672 // TODO(gc) If all evacuation candidates are too popular we 673 // should stop slots recording entirely. 674 page->ClearEvacuationCandidate(); 675 676 // We were not collecting slots on this page that point 677 // to other evacuation candidates thus we have to 678 // rescan the page after evacuation to discover and update all 679 // pointers to evacuated objects. 680 if (page->owner()->identity() == OLD_DATA_SPACE) { 681 evacuation_candidates_.RemoveElement(page); 682 } else { 683 page->SetFlag(Page::RESCAN_ON_EVACUATION); 684 } 685 } 686 687 void RecordRelocSlot(RelocInfo* rinfo, Object* target); 688 void RecordCodeEntrySlot(Address slot, Code* target); 689 void RecordCodeTargetPatch(Address pc, Code* target); 690 691 INLINE(void RecordSlot(Object** anchor_slot, Object** slot, Object* object)); 692 693 void MigrateObject(Address dst, 694 Address src, 695 int size, 696 AllocationSpace to_old_space); 697 698 bool TryPromoteObject(HeapObject* object, int object_size); 699 700 inline Object* encountered_weak_collections() { 701 return encountered_weak_collections_; 702 } 703 inline void set_encountered_weak_collections(Object* weak_collection) { 704 encountered_weak_collections_ = weak_collection; 705 } 706 707 void InvalidateCode(Code* code); 708 709 void ClearMarkbits(); 710 711 bool abort_incremental_marking() const { return abort_incremental_marking_; } 712 713 bool is_compacting() const { return compacting_; } 714 715 MarkingParity marking_parity() { return marking_parity_; } 716 717 // Concurrent and parallel sweeping support. 718 void SweepInParallel(PagedSpace* space, 719 FreeList* private_free_list, 720 FreeList* free_list); 721 722 void WaitUntilSweepingCompleted(); 723 724 intptr_t StealMemoryFromSweeperThreads(PagedSpace* space); 725 726 bool AreSweeperThreadsActivated(); 727 728 bool IsConcurrentSweepingInProgress(); 729 730 void set_sequential_sweeping(bool sequential_sweeping) { 731 sequential_sweeping_ = sequential_sweeping; 732 } 733 734 bool sequential_sweeping() const { 735 return sequential_sweeping_; 736 } 737 738 // Mark the global table which maps weak objects to dependent code without 739 // marking its contents. 740 void MarkWeakObjectToCodeTable(); 741 742 // Special case for processing weak references in a full collection. We need 743 // to artifically keep AllocationSites alive for a time. 744 void MarkAllocationSite(AllocationSite* site); 745 746 private: 747 MarkCompactCollector(); 748 ~MarkCompactCollector(); 749 750 bool MarkInvalidatedCode(); 751 bool WillBeDeoptimized(Code* code); 752 void RemoveDeadInvalidatedCode(); 753 void ProcessInvalidatedCode(ObjectVisitor* visitor); 754 755 void UnlinkEvacuationCandidates(); 756 void ReleaseEvacuationCandidates(); 757 758 void StartSweeperThreads(); 759 760 #ifdef DEBUG 761 enum CollectorState { 762 IDLE, 763 PREPARE_GC, 764 MARK_LIVE_OBJECTS, 765 SWEEP_SPACES, 766 ENCODE_FORWARDING_ADDRESSES, 767 UPDATE_POINTERS, 768 RELOCATE_OBJECTS 769 }; 770 771 // The current stage of the collector. 772 CollectorState state_; 773 #endif 774 775 // Global flag that forces sweeping to be precise, so we can traverse the 776 // heap. 777 bool sweep_precisely_; 778 779 bool reduce_memory_footprint_; 780 781 bool abort_incremental_marking_; 782 783 MarkingParity marking_parity_; 784 785 // True if we are collecting slots to perform evacuation from evacuation 786 // candidates. 787 bool compacting_; 788 789 bool was_marked_incrementally_; 790 791 // True if concurrent or parallel sweeping is currently in progress. 792 bool sweeping_pending_; 793 794 bool sequential_sweeping_; 795 796 // A pointer to the current stack-allocated GC tracer object during a full 797 // collection (NULL before and after). 798 GCTracer* tracer_; 799 800 SlotsBufferAllocator slots_buffer_allocator_; 801 802 SlotsBuffer* migration_slots_buffer_; 803 804 // Finishes GC, performs heap verification if enabled. 805 void Finish(); 806 807 // ----------------------------------------------------------------------- 808 // Phase 1: Marking live objects. 809 // 810 // Before: The heap has been prepared for garbage collection by 811 // MarkCompactCollector::Prepare() and is otherwise in its 812 // normal state. 813 // 814 // After: Live objects are marked and non-live objects are unmarked. 815 816 friend class RootMarkingVisitor; 817 friend class MarkingVisitor; 818 friend class MarkCompactMarkingVisitor; 819 friend class CodeMarkingVisitor; 820 friend class SharedFunctionInfoMarkingVisitor; 821 822 // Mark code objects that are active on the stack to prevent them 823 // from being flushed. 824 void PrepareThreadForCodeFlushing(Isolate* isolate, ThreadLocalTop* top); 825 826 void PrepareForCodeFlushing(); 827 828 // Marking operations for objects reachable from roots. 829 void MarkLiveObjects(); 830 831 void AfterMarking(); 832 833 // Marks the object black and pushes it on the marking stack. 834 // This is for non-incremental marking only. 835 INLINE(void MarkObject(HeapObject* obj, MarkBit mark_bit)); 836 837 // Marks the object black assuming that it is not yet marked. 838 // This is for non-incremental marking only. 839 INLINE(void SetMark(HeapObject* obj, MarkBit mark_bit)); 840 841 // Mark the heap roots and all objects reachable from them. 842 void MarkRoots(RootMarkingVisitor* visitor); 843 844 // Mark the string table specially. References to internalized strings from 845 // the string table are weak. 846 void MarkStringTable(RootMarkingVisitor* visitor); 847 848 // Mark objects in implicit references groups if their parent object 849 // is marked. 850 void MarkImplicitRefGroups(); 851 852 // Mark objects reachable (transitively) from objects in the marking stack 853 // or overflowed in the heap. 854 void ProcessMarkingDeque(); 855 856 // Mark objects reachable (transitively) from objects in the marking stack 857 // or overflowed in the heap. This respects references only considered in 858 // the final atomic marking pause including the following: 859 // - Processing of objects reachable through Harmony WeakMaps. 860 // - Objects reachable due to host application logic like object groups 861 // or implicit references' groups. 862 void ProcessEphemeralMarking(ObjectVisitor* visitor); 863 864 // If the call-site of the top optimized code was not prepared for 865 // deoptimization, then treat the maps in the code as strong pointers, 866 // otherwise a map can die and deoptimize the code. 867 void ProcessTopOptimizedFrame(ObjectVisitor* visitor); 868 869 // Mark objects reachable (transitively) from objects in the marking 870 // stack. This function empties the marking stack, but may leave 871 // overflowed objects in the heap, in which case the marking stack's 872 // overflow flag will be set. 873 void EmptyMarkingDeque(); 874 875 // Refill the marking stack with overflowed objects from the heap. This 876 // function either leaves the marking stack full or clears the overflow 877 // flag on the marking stack. 878 void RefillMarkingDeque(); 879 880 // After reachable maps have been marked process per context object 881 // literal map caches removing unmarked entries. 882 void ProcessMapCaches(); 883 884 // Callback function for telling whether the object *p is an unmarked 885 // heap object. 886 static bool IsUnmarkedHeapObject(Object** p); 887 static bool IsUnmarkedHeapObjectWithHeap(Heap* heap, Object** p); 888 889 // Map transitions from a live map to a dead map must be killed. 890 // We replace them with a null descriptor, with the same key. 891 void ClearNonLiveReferences(); 892 void ClearNonLivePrototypeTransitions(Map* map); 893 void ClearNonLiveMapTransitions(Map* map, MarkBit map_mark); 894 895 void ClearAndDeoptimizeDependentCode(DependentCode* dependent_code); 896 void ClearNonLiveDependentCode(DependentCode* dependent_code); 897 898 // Marking detaches initial maps from SharedFunctionInfo objects 899 // to make this reference weak. We need to reattach initial maps 900 // back after collection. This is either done during 901 // ClearNonLiveTransitions pass or by calling this function. 902 void ReattachInitialMaps(); 903 904 // Mark all values associated with reachable keys in weak collections 905 // encountered so far. This might push new object or even new weak maps onto 906 // the marking stack. 907 void ProcessWeakCollections(); 908 909 // After all reachable objects have been marked those weak map entries 910 // with an unreachable key are removed from all encountered weak maps. 911 // The linked list of all encountered weak maps is destroyed. 912 void ClearWeakCollections(); 913 914 // ----------------------------------------------------------------------- 915 // Phase 2: Sweeping to clear mark bits and free non-live objects for 916 // a non-compacting collection. 917 // 918 // Before: Live objects are marked and non-live objects are unmarked. 919 // 920 // After: Live objects are unmarked, non-live regions have been added to 921 // their space's free list. Active eden semispace is compacted by 922 // evacuation. 923 // 924 925 // If we are not compacting the heap, we simply sweep the spaces except 926 // for the large object space, clearing mark bits and adding unmarked 927 // regions to each space's free list. 928 void SweepSpaces(); 929 930 int DiscoverAndPromoteBlackObjectsOnPage(NewSpace* new_space, 931 NewSpacePage* p); 932 933 void EvacuateNewSpace(); 934 935 void EvacuateLiveObjectsFromPage(Page* p); 936 937 void EvacuatePages(); 938 939 void EvacuateNewSpaceAndCandidates(); 940 941 void SweepSpace(PagedSpace* space, SweeperType sweeper); 942 943 #ifdef DEBUG 944 friend class MarkObjectVisitor; 945 static void VisitObject(HeapObject* obj); 946 947 friend class UnmarkObjectVisitor; 948 static void UnmarkObject(HeapObject* obj); 949 #endif 950 951 Heap* heap_; 952 MarkingDeque marking_deque_; 953 CodeFlusher* code_flusher_; 954 Object* encountered_weak_collections_; 955 bool have_code_to_deoptimize_; 956 957 List<Page*> evacuation_candidates_; 958 List<Code*> invalidated_code_; 959 960 friend class Heap; 961 }; 962 963 964 class MarkBitCellIterator BASE_EMBEDDED { 965 public: 966 explicit MarkBitCellIterator(MemoryChunk* chunk) 967 : chunk_(chunk) { 968 last_cell_index_ = Bitmap::IndexToCell( 969 Bitmap::CellAlignIndex( 970 chunk_->AddressToMarkbitIndex(chunk_->area_end()))); 971 cell_base_ = chunk_->area_start(); 972 cell_index_ = Bitmap::IndexToCell( 973 Bitmap::CellAlignIndex( 974 chunk_->AddressToMarkbitIndex(cell_base_))); 975 cells_ = chunk_->markbits()->cells(); 976 } 977 978 inline bool Done() { return cell_index_ == last_cell_index_; } 979 980 inline bool HasNext() { return cell_index_ < last_cell_index_ - 1; } 981 982 inline MarkBit::CellType* CurrentCell() { 983 ASSERT(cell_index_ == Bitmap::IndexToCell(Bitmap::CellAlignIndex( 984 chunk_->AddressToMarkbitIndex(cell_base_)))); 985 return &cells_[cell_index_]; 986 } 987 988 inline Address CurrentCellBase() { 989 ASSERT(cell_index_ == Bitmap::IndexToCell(Bitmap::CellAlignIndex( 990 chunk_->AddressToMarkbitIndex(cell_base_)))); 991 return cell_base_; 992 } 993 994 inline void Advance() { 995 cell_index_++; 996 cell_base_ += 32 * kPointerSize; 997 } 998 999 private: 1000 MemoryChunk* chunk_; 1001 MarkBit::CellType* cells_; 1002 unsigned int last_cell_index_; 1003 unsigned int cell_index_; 1004 Address cell_base_; 1005 }; 1006 1007 1008 class SequentialSweepingScope BASE_EMBEDDED { 1009 public: 1010 explicit SequentialSweepingScope(MarkCompactCollector *collector) : 1011 collector_(collector) { 1012 collector_->set_sequential_sweeping(true); 1013 } 1014 1015 ~SequentialSweepingScope() { 1016 collector_->set_sequential_sweeping(false); 1017 } 1018 1019 private: 1020 MarkCompactCollector* collector_; 1021 }; 1022 1023 1024 const char* AllocationSpaceName(AllocationSpace space); 1025 1026 } } // namespace v8::internal 1027 1028 #endif // V8_MARK_COMPACT_H_ 1029