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 #include "v8.h" 29 30 #include "code-stubs.h" 31 #include "compilation-cache.h" 32 #include "cpu-profiler.h" 33 #include "deoptimizer.h" 34 #include "execution.h" 35 #include "gdb-jit.h" 36 #include "global-handles.h" 37 #include "heap-profiler.h" 38 #include "ic-inl.h" 39 #include "incremental-marking.h" 40 #include "mark-compact.h" 41 #include "objects-visiting.h" 42 #include "objects-visiting-inl.h" 43 #include "stub-cache.h" 44 #include "sweeper-thread.h" 45 46 namespace v8 { 47 namespace internal { 48 49 50 const char* Marking::kWhiteBitPattern = "00"; 51 const char* Marking::kBlackBitPattern = "10"; 52 const char* Marking::kGreyBitPattern = "11"; 53 const char* Marking::kImpossibleBitPattern = "01"; 54 55 56 // ------------------------------------------------------------------------- 57 // MarkCompactCollector 58 59 MarkCompactCollector::MarkCompactCollector() : // NOLINT 60 #ifdef DEBUG 61 state_(IDLE), 62 #endif 63 sweep_precisely_(false), 64 reduce_memory_footprint_(false), 65 abort_incremental_marking_(false), 66 marking_parity_(ODD_MARKING_PARITY), 67 compacting_(false), 68 was_marked_incrementally_(false), 69 sweeping_pending_(false), 70 sequential_sweeping_(false), 71 tracer_(NULL), 72 migration_slots_buffer_(NULL), 73 heap_(NULL), 74 code_flusher_(NULL), 75 encountered_weak_collections_(NULL), 76 have_code_to_deoptimize_(false) { } 77 78 #ifdef VERIFY_HEAP 79 class VerifyMarkingVisitor: public ObjectVisitor { 80 public: 81 explicit VerifyMarkingVisitor(Heap* heap) : heap_(heap) {} 82 83 void VisitPointers(Object** start, Object** end) { 84 for (Object** current = start; current < end; current++) { 85 if ((*current)->IsHeapObject()) { 86 HeapObject* object = HeapObject::cast(*current); 87 CHECK(heap_->mark_compact_collector()->IsMarked(object)); 88 } 89 } 90 } 91 92 void VisitEmbeddedPointer(RelocInfo* rinfo) { 93 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); 94 if (!Code::IsWeakEmbeddedObject(rinfo->host()->kind(), 95 rinfo->target_object())) { 96 Object* p = rinfo->target_object(); 97 VisitPointer(&p); 98 } 99 } 100 101 private: 102 Heap* heap_; 103 }; 104 105 106 static void VerifyMarking(Heap* heap, Address bottom, Address top) { 107 VerifyMarkingVisitor visitor(heap); 108 HeapObject* object; 109 Address next_object_must_be_here_or_later = bottom; 110 111 for (Address current = bottom; 112 current < top; 113 current += kPointerSize) { 114 object = HeapObject::FromAddress(current); 115 if (MarkCompactCollector::IsMarked(object)) { 116 CHECK(current >= next_object_must_be_here_or_later); 117 object->Iterate(&visitor); 118 next_object_must_be_here_or_later = current + object->Size(); 119 } 120 } 121 } 122 123 124 static void VerifyMarking(NewSpace* space) { 125 Address end = space->top(); 126 NewSpacePageIterator it(space->bottom(), end); 127 // The bottom position is at the start of its page. Allows us to use 128 // page->area_start() as start of range on all pages. 129 CHECK_EQ(space->bottom(), 130 NewSpacePage::FromAddress(space->bottom())->area_start()); 131 while (it.has_next()) { 132 NewSpacePage* page = it.next(); 133 Address limit = it.has_next() ? page->area_end() : end; 134 CHECK(limit == end || !page->Contains(end)); 135 VerifyMarking(space->heap(), page->area_start(), limit); 136 } 137 } 138 139 140 static void VerifyMarking(PagedSpace* space) { 141 PageIterator it(space); 142 143 while (it.has_next()) { 144 Page* p = it.next(); 145 VerifyMarking(space->heap(), p->area_start(), p->area_end()); 146 } 147 } 148 149 150 static void VerifyMarking(Heap* heap) { 151 VerifyMarking(heap->old_pointer_space()); 152 VerifyMarking(heap->old_data_space()); 153 VerifyMarking(heap->code_space()); 154 VerifyMarking(heap->cell_space()); 155 VerifyMarking(heap->property_cell_space()); 156 VerifyMarking(heap->map_space()); 157 VerifyMarking(heap->new_space()); 158 159 VerifyMarkingVisitor visitor(heap); 160 161 LargeObjectIterator it(heap->lo_space()); 162 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) { 163 if (MarkCompactCollector::IsMarked(obj)) { 164 obj->Iterate(&visitor); 165 } 166 } 167 168 heap->IterateStrongRoots(&visitor, VISIT_ONLY_STRONG); 169 } 170 171 172 class VerifyEvacuationVisitor: public ObjectVisitor { 173 public: 174 void VisitPointers(Object** start, Object** end) { 175 for (Object** current = start; current < end; current++) { 176 if ((*current)->IsHeapObject()) { 177 HeapObject* object = HeapObject::cast(*current); 178 CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(object)); 179 } 180 } 181 } 182 }; 183 184 185 static void VerifyEvacuation(Address bottom, Address top) { 186 VerifyEvacuationVisitor visitor; 187 HeapObject* object; 188 Address next_object_must_be_here_or_later = bottom; 189 190 for (Address current = bottom; 191 current < top; 192 current += kPointerSize) { 193 object = HeapObject::FromAddress(current); 194 if (MarkCompactCollector::IsMarked(object)) { 195 CHECK(current >= next_object_must_be_here_or_later); 196 object->Iterate(&visitor); 197 next_object_must_be_here_or_later = current + object->Size(); 198 } 199 } 200 } 201 202 203 static void VerifyEvacuation(NewSpace* space) { 204 NewSpacePageIterator it(space->bottom(), space->top()); 205 VerifyEvacuationVisitor visitor; 206 207 while (it.has_next()) { 208 NewSpacePage* page = it.next(); 209 Address current = page->area_start(); 210 Address limit = it.has_next() ? page->area_end() : space->top(); 211 CHECK(limit == space->top() || !page->Contains(space->top())); 212 while (current < limit) { 213 HeapObject* object = HeapObject::FromAddress(current); 214 object->Iterate(&visitor); 215 current += object->Size(); 216 } 217 } 218 } 219 220 221 static void VerifyEvacuation(PagedSpace* space) { 222 PageIterator it(space); 223 224 while (it.has_next()) { 225 Page* p = it.next(); 226 if (p->IsEvacuationCandidate()) continue; 227 VerifyEvacuation(p->area_start(), p->area_end()); 228 } 229 } 230 231 232 static void VerifyEvacuation(Heap* heap) { 233 VerifyEvacuation(heap->old_pointer_space()); 234 VerifyEvacuation(heap->old_data_space()); 235 VerifyEvacuation(heap->code_space()); 236 VerifyEvacuation(heap->cell_space()); 237 VerifyEvacuation(heap->property_cell_space()); 238 VerifyEvacuation(heap->map_space()); 239 VerifyEvacuation(heap->new_space()); 240 241 VerifyEvacuationVisitor visitor; 242 heap->IterateStrongRoots(&visitor, VISIT_ALL); 243 } 244 #endif // VERIFY_HEAP 245 246 247 #ifdef DEBUG 248 class VerifyNativeContextSeparationVisitor: public ObjectVisitor { 249 public: 250 VerifyNativeContextSeparationVisitor() : current_native_context_(NULL) {} 251 252 void VisitPointers(Object** start, Object** end) { 253 for (Object** current = start; current < end; current++) { 254 if ((*current)->IsHeapObject()) { 255 HeapObject* object = HeapObject::cast(*current); 256 if (object->IsString()) continue; 257 switch (object->map()->instance_type()) { 258 case JS_FUNCTION_TYPE: 259 CheckContext(JSFunction::cast(object)->context()); 260 break; 261 case JS_GLOBAL_PROXY_TYPE: 262 CheckContext(JSGlobalProxy::cast(object)->native_context()); 263 break; 264 case JS_GLOBAL_OBJECT_TYPE: 265 case JS_BUILTINS_OBJECT_TYPE: 266 CheckContext(GlobalObject::cast(object)->native_context()); 267 break; 268 case JS_ARRAY_TYPE: 269 case JS_DATE_TYPE: 270 case JS_OBJECT_TYPE: 271 case JS_REGEXP_TYPE: 272 VisitPointer(HeapObject::RawField(object, JSObject::kMapOffset)); 273 break; 274 case MAP_TYPE: 275 VisitPointer(HeapObject::RawField(object, Map::kPrototypeOffset)); 276 VisitPointer(HeapObject::RawField(object, Map::kConstructorOffset)); 277 break; 278 case FIXED_ARRAY_TYPE: 279 if (object->IsContext()) { 280 CheckContext(object); 281 } else { 282 FixedArray* array = FixedArray::cast(object); 283 int length = array->length(); 284 // Set array length to zero to prevent cycles while iterating 285 // over array bodies, this is easier than intrusive marking. 286 array->set_length(0); 287 array->IterateBody( 288 FIXED_ARRAY_TYPE, FixedArray::SizeFor(length), this); 289 array->set_length(length); 290 } 291 break; 292 case CELL_TYPE: 293 case JS_PROXY_TYPE: 294 case JS_VALUE_TYPE: 295 case TYPE_FEEDBACK_INFO_TYPE: 296 object->Iterate(this); 297 break; 298 case DECLARED_ACCESSOR_INFO_TYPE: 299 case EXECUTABLE_ACCESSOR_INFO_TYPE: 300 case BYTE_ARRAY_TYPE: 301 case CALL_HANDLER_INFO_TYPE: 302 case CODE_TYPE: 303 case FIXED_DOUBLE_ARRAY_TYPE: 304 case HEAP_NUMBER_TYPE: 305 case INTERCEPTOR_INFO_TYPE: 306 case ODDBALL_TYPE: 307 case SCRIPT_TYPE: 308 case SHARED_FUNCTION_INFO_TYPE: 309 break; 310 default: 311 UNREACHABLE(); 312 } 313 } 314 } 315 } 316 317 private: 318 void CheckContext(Object* context) { 319 if (!context->IsContext()) return; 320 Context* native_context = Context::cast(context)->native_context(); 321 if (current_native_context_ == NULL) { 322 current_native_context_ = native_context; 323 } else { 324 CHECK_EQ(current_native_context_, native_context); 325 } 326 } 327 328 Context* current_native_context_; 329 }; 330 331 332 static void VerifyNativeContextSeparation(Heap* heap) { 333 HeapObjectIterator it(heap->code_space()); 334 335 for (Object* object = it.Next(); object != NULL; object = it.Next()) { 336 VerifyNativeContextSeparationVisitor visitor; 337 Code::cast(object)->CodeIterateBody(&visitor); 338 } 339 } 340 #endif 341 342 343 void MarkCompactCollector::TearDown() { 344 AbortCompaction(); 345 } 346 347 348 void MarkCompactCollector::AddEvacuationCandidate(Page* p) { 349 p->MarkEvacuationCandidate(); 350 evacuation_candidates_.Add(p); 351 } 352 353 354 static void TraceFragmentation(PagedSpace* space) { 355 int number_of_pages = space->CountTotalPages(); 356 intptr_t reserved = (number_of_pages * space->AreaSize()); 357 intptr_t free = reserved - space->SizeOfObjects(); 358 PrintF("[%s]: %d pages, %d (%.1f%%) free\n", 359 AllocationSpaceName(space->identity()), 360 number_of_pages, 361 static_cast<int>(free), 362 static_cast<double>(free) * 100 / reserved); 363 } 364 365 366 bool MarkCompactCollector::StartCompaction(CompactionMode mode) { 367 if (!compacting_) { 368 ASSERT(evacuation_candidates_.length() == 0); 369 370 #ifdef ENABLE_GDB_JIT_INTERFACE 371 // If GDBJIT interface is active disable compaction. 372 if (FLAG_gdbjit) return false; 373 #endif 374 375 CollectEvacuationCandidates(heap()->old_pointer_space()); 376 CollectEvacuationCandidates(heap()->old_data_space()); 377 378 if (FLAG_compact_code_space && 379 (mode == NON_INCREMENTAL_COMPACTION || 380 FLAG_incremental_code_compaction)) { 381 CollectEvacuationCandidates(heap()->code_space()); 382 } else if (FLAG_trace_fragmentation) { 383 TraceFragmentation(heap()->code_space()); 384 } 385 386 if (FLAG_trace_fragmentation) { 387 TraceFragmentation(heap()->map_space()); 388 TraceFragmentation(heap()->cell_space()); 389 TraceFragmentation(heap()->property_cell_space()); 390 } 391 392 heap()->old_pointer_space()->EvictEvacuationCandidatesFromFreeLists(); 393 heap()->old_data_space()->EvictEvacuationCandidatesFromFreeLists(); 394 heap()->code_space()->EvictEvacuationCandidatesFromFreeLists(); 395 396 compacting_ = evacuation_candidates_.length() > 0; 397 } 398 399 return compacting_; 400 } 401 402 403 void MarkCompactCollector::CollectGarbage() { 404 // Make sure that Prepare() has been called. The individual steps below will 405 // update the state as they proceed. 406 ASSERT(state_ == PREPARE_GC); 407 ASSERT(encountered_weak_collections_ == Smi::FromInt(0)); 408 409 MarkLiveObjects(); 410 ASSERT(heap_->incremental_marking()->IsStopped()); 411 412 if (FLAG_collect_maps) ClearNonLiveReferences(); 413 414 ClearWeakCollections(); 415 416 #ifdef VERIFY_HEAP 417 if (FLAG_verify_heap) { 418 VerifyMarking(heap_); 419 } 420 #endif 421 422 SweepSpaces(); 423 424 if (!FLAG_collect_maps) ReattachInitialMaps(); 425 426 #ifdef DEBUG 427 if (FLAG_verify_native_context_separation) { 428 VerifyNativeContextSeparation(heap_); 429 } 430 #endif 431 432 #ifdef VERIFY_HEAP 433 if (heap()->weak_embedded_objects_verification_enabled()) { 434 VerifyWeakEmbeddedObjectsInOptimizedCode(); 435 } 436 if (FLAG_collect_maps && FLAG_omit_map_checks_for_leaf_maps) { 437 VerifyOmittedMapChecks(); 438 } 439 #endif 440 441 Finish(); 442 443 if (marking_parity_ == EVEN_MARKING_PARITY) { 444 marking_parity_ = ODD_MARKING_PARITY; 445 } else { 446 ASSERT(marking_parity_ == ODD_MARKING_PARITY); 447 marking_parity_ = EVEN_MARKING_PARITY; 448 } 449 450 tracer_ = NULL; 451 } 452 453 454 #ifdef VERIFY_HEAP 455 void MarkCompactCollector::VerifyMarkbitsAreClean(PagedSpace* space) { 456 PageIterator it(space); 457 458 while (it.has_next()) { 459 Page* p = it.next(); 460 CHECK(p->markbits()->IsClean()); 461 CHECK_EQ(0, p->LiveBytes()); 462 } 463 } 464 465 466 void MarkCompactCollector::VerifyMarkbitsAreClean(NewSpace* space) { 467 NewSpacePageIterator it(space->bottom(), space->top()); 468 469 while (it.has_next()) { 470 NewSpacePage* p = it.next(); 471 CHECK(p->markbits()->IsClean()); 472 CHECK_EQ(0, p->LiveBytes()); 473 } 474 } 475 476 477 void MarkCompactCollector::VerifyMarkbitsAreClean() { 478 VerifyMarkbitsAreClean(heap_->old_pointer_space()); 479 VerifyMarkbitsAreClean(heap_->old_data_space()); 480 VerifyMarkbitsAreClean(heap_->code_space()); 481 VerifyMarkbitsAreClean(heap_->cell_space()); 482 VerifyMarkbitsAreClean(heap_->property_cell_space()); 483 VerifyMarkbitsAreClean(heap_->map_space()); 484 VerifyMarkbitsAreClean(heap_->new_space()); 485 486 LargeObjectIterator it(heap_->lo_space()); 487 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) { 488 MarkBit mark_bit = Marking::MarkBitFrom(obj); 489 CHECK(Marking::IsWhite(mark_bit)); 490 CHECK_EQ(0, Page::FromAddress(obj->address())->LiveBytes()); 491 } 492 } 493 494 495 void MarkCompactCollector::VerifyWeakEmbeddedObjectsInOptimizedCode() { 496 HeapObjectIterator code_iterator(heap()->code_space()); 497 for (HeapObject* obj = code_iterator.Next(); 498 obj != NULL; 499 obj = code_iterator.Next()) { 500 Code* code = Code::cast(obj); 501 if (code->kind() != Code::OPTIMIZED_FUNCTION) continue; 502 if (WillBeDeoptimized(code)) continue; 503 code->VerifyEmbeddedObjectsDependency(); 504 } 505 } 506 507 508 void MarkCompactCollector::VerifyOmittedMapChecks() { 509 HeapObjectIterator iterator(heap()->map_space()); 510 for (HeapObject* obj = iterator.Next(); 511 obj != NULL; 512 obj = iterator.Next()) { 513 Map* map = Map::cast(obj); 514 map->VerifyOmittedMapChecks(); 515 } 516 } 517 #endif // VERIFY_HEAP 518 519 520 static void ClearMarkbitsInPagedSpace(PagedSpace* space) { 521 PageIterator it(space); 522 523 while (it.has_next()) { 524 Bitmap::Clear(it.next()); 525 } 526 } 527 528 529 static void ClearMarkbitsInNewSpace(NewSpace* space) { 530 NewSpacePageIterator it(space->ToSpaceStart(), space->ToSpaceEnd()); 531 532 while (it.has_next()) { 533 Bitmap::Clear(it.next()); 534 } 535 } 536 537 538 void MarkCompactCollector::ClearMarkbits() { 539 ClearMarkbitsInPagedSpace(heap_->code_space()); 540 ClearMarkbitsInPagedSpace(heap_->map_space()); 541 ClearMarkbitsInPagedSpace(heap_->old_pointer_space()); 542 ClearMarkbitsInPagedSpace(heap_->old_data_space()); 543 ClearMarkbitsInPagedSpace(heap_->cell_space()); 544 ClearMarkbitsInPagedSpace(heap_->property_cell_space()); 545 ClearMarkbitsInNewSpace(heap_->new_space()); 546 547 LargeObjectIterator it(heap_->lo_space()); 548 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) { 549 MarkBit mark_bit = Marking::MarkBitFrom(obj); 550 mark_bit.Clear(); 551 mark_bit.Next().Clear(); 552 Page::FromAddress(obj->address())->ResetProgressBar(); 553 Page::FromAddress(obj->address())->ResetLiveBytes(); 554 } 555 } 556 557 558 void MarkCompactCollector::StartSweeperThreads() { 559 sweeping_pending_ = true; 560 for (int i = 0; i < isolate()->num_sweeper_threads(); i++) { 561 isolate()->sweeper_threads()[i]->StartSweeping(); 562 } 563 } 564 565 566 void MarkCompactCollector::WaitUntilSweepingCompleted() { 567 ASSERT(sweeping_pending_ == true); 568 for (int i = 0; i < isolate()->num_sweeper_threads(); i++) { 569 isolate()->sweeper_threads()[i]->WaitForSweeperThread(); 570 } 571 sweeping_pending_ = false; 572 StealMemoryFromSweeperThreads(heap()->paged_space(OLD_DATA_SPACE)); 573 StealMemoryFromSweeperThreads(heap()->paged_space(OLD_POINTER_SPACE)); 574 heap()->paged_space(OLD_DATA_SPACE)->ResetUnsweptFreeBytes(); 575 heap()->paged_space(OLD_POINTER_SPACE)->ResetUnsweptFreeBytes(); 576 } 577 578 579 intptr_t MarkCompactCollector:: 580 StealMemoryFromSweeperThreads(PagedSpace* space) { 581 intptr_t freed_bytes = 0; 582 for (int i = 0; i < isolate()->num_sweeper_threads(); i++) { 583 freed_bytes += isolate()->sweeper_threads()[i]->StealMemory(space); 584 } 585 space->AddToAccountingStats(freed_bytes); 586 space->DecrementUnsweptFreeBytes(freed_bytes); 587 return freed_bytes; 588 } 589 590 591 bool MarkCompactCollector::AreSweeperThreadsActivated() { 592 return isolate()->sweeper_threads() != NULL; 593 } 594 595 596 bool MarkCompactCollector::IsConcurrentSweepingInProgress() { 597 return sweeping_pending_; 598 } 599 600 601 bool Marking::TransferMark(Address old_start, Address new_start) { 602 // This is only used when resizing an object. 603 ASSERT(MemoryChunk::FromAddress(old_start) == 604 MemoryChunk::FromAddress(new_start)); 605 606 // If the mark doesn't move, we don't check the color of the object. 607 // It doesn't matter whether the object is black, since it hasn't changed 608 // size, so the adjustment to the live data count will be zero anyway. 609 if (old_start == new_start) return false; 610 611 MarkBit new_mark_bit = MarkBitFrom(new_start); 612 MarkBit old_mark_bit = MarkBitFrom(old_start); 613 614 #ifdef DEBUG 615 ObjectColor old_color = Color(old_mark_bit); 616 #endif 617 618 if (Marking::IsBlack(old_mark_bit)) { 619 old_mark_bit.Clear(); 620 ASSERT(IsWhite(old_mark_bit)); 621 Marking::MarkBlack(new_mark_bit); 622 return true; 623 } else if (Marking::IsGrey(old_mark_bit)) { 624 ASSERT(heap_->incremental_marking()->IsMarking()); 625 old_mark_bit.Clear(); 626 old_mark_bit.Next().Clear(); 627 ASSERT(IsWhite(old_mark_bit)); 628 heap_->incremental_marking()->WhiteToGreyAndPush( 629 HeapObject::FromAddress(new_start), new_mark_bit); 630 heap_->incremental_marking()->RestartIfNotMarking(); 631 } 632 633 #ifdef DEBUG 634 ObjectColor new_color = Color(new_mark_bit); 635 ASSERT(new_color == old_color); 636 #endif 637 638 return false; 639 } 640 641 642 const char* AllocationSpaceName(AllocationSpace space) { 643 switch (space) { 644 case NEW_SPACE: return "NEW_SPACE"; 645 case OLD_POINTER_SPACE: return "OLD_POINTER_SPACE"; 646 case OLD_DATA_SPACE: return "OLD_DATA_SPACE"; 647 case CODE_SPACE: return "CODE_SPACE"; 648 case MAP_SPACE: return "MAP_SPACE"; 649 case CELL_SPACE: return "CELL_SPACE"; 650 case PROPERTY_CELL_SPACE: 651 return "PROPERTY_CELL_SPACE"; 652 case LO_SPACE: return "LO_SPACE"; 653 default: 654 UNREACHABLE(); 655 } 656 657 return NULL; 658 } 659 660 661 // Returns zero for pages that have so little fragmentation that it is not 662 // worth defragmenting them. Otherwise a positive integer that gives an 663 // estimate of fragmentation on an arbitrary scale. 664 static int FreeListFragmentation(PagedSpace* space, Page* p) { 665 // If page was not swept then there are no free list items on it. 666 if (!p->WasSwept()) { 667 if (FLAG_trace_fragmentation) { 668 PrintF("%p [%s]: %d bytes live (unswept)\n", 669 reinterpret_cast<void*>(p), 670 AllocationSpaceName(space->identity()), 671 p->LiveBytes()); 672 } 673 return 0; 674 } 675 676 PagedSpace::SizeStats sizes; 677 space->ObtainFreeListStatistics(p, &sizes); 678 679 intptr_t ratio; 680 intptr_t ratio_threshold; 681 intptr_t area_size = space->AreaSize(); 682 if (space->identity() == CODE_SPACE) { 683 ratio = (sizes.medium_size_ * 10 + sizes.large_size_ * 2) * 100 / 684 area_size; 685 ratio_threshold = 10; 686 } else { 687 ratio = (sizes.small_size_ * 5 + sizes.medium_size_) * 100 / 688 area_size; 689 ratio_threshold = 15; 690 } 691 692 if (FLAG_trace_fragmentation) { 693 PrintF("%p [%s]: %d (%.2f%%) %d (%.2f%%) %d (%.2f%%) %d (%.2f%%) %s\n", 694 reinterpret_cast<void*>(p), 695 AllocationSpaceName(space->identity()), 696 static_cast<int>(sizes.small_size_), 697 static_cast<double>(sizes.small_size_ * 100) / 698 area_size, 699 static_cast<int>(sizes.medium_size_), 700 static_cast<double>(sizes.medium_size_ * 100) / 701 area_size, 702 static_cast<int>(sizes.large_size_), 703 static_cast<double>(sizes.large_size_ * 100) / 704 area_size, 705 static_cast<int>(sizes.huge_size_), 706 static_cast<double>(sizes.huge_size_ * 100) / 707 area_size, 708 (ratio > ratio_threshold) ? "[fragmented]" : ""); 709 } 710 711 if (FLAG_always_compact && sizes.Total() != area_size) { 712 return 1; 713 } 714 715 if (ratio <= ratio_threshold) return 0; // Not fragmented. 716 717 return static_cast<int>(ratio - ratio_threshold); 718 } 719 720 721 void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) { 722 ASSERT(space->identity() == OLD_POINTER_SPACE || 723 space->identity() == OLD_DATA_SPACE || 724 space->identity() == CODE_SPACE); 725 726 static const int kMaxMaxEvacuationCandidates = 1000; 727 int number_of_pages = space->CountTotalPages(); 728 int max_evacuation_candidates = 729 static_cast<int>(sqrt(number_of_pages / 2.0) + 1); 730 731 if (FLAG_stress_compaction || FLAG_always_compact) { 732 max_evacuation_candidates = kMaxMaxEvacuationCandidates; 733 } 734 735 class Candidate { 736 public: 737 Candidate() : fragmentation_(0), page_(NULL) { } 738 Candidate(int f, Page* p) : fragmentation_(f), page_(p) { } 739 740 int fragmentation() { return fragmentation_; } 741 Page* page() { return page_; } 742 743 private: 744 int fragmentation_; 745 Page* page_; 746 }; 747 748 enum CompactionMode { 749 COMPACT_FREE_LISTS, 750 REDUCE_MEMORY_FOOTPRINT 751 }; 752 753 CompactionMode mode = COMPACT_FREE_LISTS; 754 755 intptr_t reserved = number_of_pages * space->AreaSize(); 756 intptr_t over_reserved = reserved - space->SizeOfObjects(); 757 static const intptr_t kFreenessThreshold = 50; 758 759 if (reduce_memory_footprint_ && over_reserved >= space->AreaSize()) { 760 // If reduction of memory footprint was requested, we are aggressive 761 // about choosing pages to free. We expect that half-empty pages 762 // are easier to compact so slightly bump the limit. 763 mode = REDUCE_MEMORY_FOOTPRINT; 764 max_evacuation_candidates += 2; 765 } 766 767 768 if (over_reserved > reserved / 3 && over_reserved >= 2 * space->AreaSize()) { 769 // If over-usage is very high (more than a third of the space), we 770 // try to free all mostly empty pages. We expect that almost empty 771 // pages are even easier to compact so bump the limit even more. 772 mode = REDUCE_MEMORY_FOOTPRINT; 773 max_evacuation_candidates *= 2; 774 } 775 776 if (FLAG_trace_fragmentation && mode == REDUCE_MEMORY_FOOTPRINT) { 777 PrintF("Estimated over reserved memory: %.1f / %.1f MB (threshold %d), " 778 "evacuation candidate limit: %d\n", 779 static_cast<double>(over_reserved) / MB, 780 static_cast<double>(reserved) / MB, 781 static_cast<int>(kFreenessThreshold), 782 max_evacuation_candidates); 783 } 784 785 intptr_t estimated_release = 0; 786 787 Candidate candidates[kMaxMaxEvacuationCandidates]; 788 789 max_evacuation_candidates = 790 Min(kMaxMaxEvacuationCandidates, max_evacuation_candidates); 791 792 int count = 0; 793 int fragmentation = 0; 794 Candidate* least = NULL; 795 796 PageIterator it(space); 797 if (it.has_next()) it.next(); // Never compact the first page. 798 799 while (it.has_next()) { 800 Page* p = it.next(); 801 p->ClearEvacuationCandidate(); 802 803 if (FLAG_stress_compaction) { 804 unsigned int counter = space->heap()->ms_count(); 805 uintptr_t page_number = reinterpret_cast<uintptr_t>(p) >> kPageSizeBits; 806 if ((counter & 1) == (page_number & 1)) fragmentation = 1; 807 } else if (mode == REDUCE_MEMORY_FOOTPRINT) { 808 // Don't try to release too many pages. 809 if (estimated_release >= over_reserved) { 810 continue; 811 } 812 813 intptr_t free_bytes = 0; 814 815 if (!p->WasSwept()) { 816 free_bytes = (p->area_size() - p->LiveBytes()); 817 } else { 818 PagedSpace::SizeStats sizes; 819 space->ObtainFreeListStatistics(p, &sizes); 820 free_bytes = sizes.Total(); 821 } 822 823 int free_pct = static_cast<int>(free_bytes * 100) / p->area_size(); 824 825 if (free_pct >= kFreenessThreshold) { 826 estimated_release += free_bytes; 827 fragmentation = free_pct; 828 } else { 829 fragmentation = 0; 830 } 831 832 if (FLAG_trace_fragmentation) { 833 PrintF("%p [%s]: %d (%.2f%%) free %s\n", 834 reinterpret_cast<void*>(p), 835 AllocationSpaceName(space->identity()), 836 static_cast<int>(free_bytes), 837 static_cast<double>(free_bytes * 100) / p->area_size(), 838 (fragmentation > 0) ? "[fragmented]" : ""); 839 } 840 } else { 841 fragmentation = FreeListFragmentation(space, p); 842 } 843 844 if (fragmentation != 0) { 845 if (count < max_evacuation_candidates) { 846 candidates[count++] = Candidate(fragmentation, p); 847 } else { 848 if (least == NULL) { 849 for (int i = 0; i < max_evacuation_candidates; i++) { 850 if (least == NULL || 851 candidates[i].fragmentation() < least->fragmentation()) { 852 least = candidates + i; 853 } 854 } 855 } 856 if (least->fragmentation() < fragmentation) { 857 *least = Candidate(fragmentation, p); 858 least = NULL; 859 } 860 } 861 } 862 } 863 864 for (int i = 0; i < count; i++) { 865 AddEvacuationCandidate(candidates[i].page()); 866 } 867 868 if (count > 0 && FLAG_trace_fragmentation) { 869 PrintF("Collected %d evacuation candidates for space %s\n", 870 count, 871 AllocationSpaceName(space->identity())); 872 } 873 } 874 875 876 void MarkCompactCollector::AbortCompaction() { 877 if (compacting_) { 878 int npages = evacuation_candidates_.length(); 879 for (int i = 0; i < npages; i++) { 880 Page* p = evacuation_candidates_[i]; 881 slots_buffer_allocator_.DeallocateChain(p->slots_buffer_address()); 882 p->ClearEvacuationCandidate(); 883 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); 884 } 885 compacting_ = false; 886 evacuation_candidates_.Rewind(0); 887 invalidated_code_.Rewind(0); 888 } 889 ASSERT_EQ(0, evacuation_candidates_.length()); 890 } 891 892 893 void MarkCompactCollector::Prepare(GCTracer* tracer) { 894 was_marked_incrementally_ = heap()->incremental_marking()->IsMarking(); 895 896 // Rather than passing the tracer around we stash it in a static member 897 // variable. 898 tracer_ = tracer; 899 900 #ifdef DEBUG 901 ASSERT(state_ == IDLE); 902 state_ = PREPARE_GC; 903 #endif 904 905 ASSERT(!FLAG_never_compact || !FLAG_always_compact); 906 907 if (IsConcurrentSweepingInProgress()) { 908 // Instead of waiting we could also abort the sweeper threads here. 909 WaitUntilSweepingCompleted(); 910 } 911 912 // Clear marking bits if incremental marking is aborted. 913 if (was_marked_incrementally_ && abort_incremental_marking_) { 914 heap()->incremental_marking()->Abort(); 915 ClearMarkbits(); 916 AbortCompaction(); 917 was_marked_incrementally_ = false; 918 } 919 920 // Don't start compaction if we are in the middle of incremental 921 // marking cycle. We did not collect any slots. 922 if (!FLAG_never_compact && !was_marked_incrementally_) { 923 StartCompaction(NON_INCREMENTAL_COMPACTION); 924 } 925 926 PagedSpaces spaces(heap()); 927 for (PagedSpace* space = spaces.next(); 928 space != NULL; 929 space = spaces.next()) { 930 space->PrepareForMarkCompact(); 931 } 932 933 #ifdef VERIFY_HEAP 934 if (!was_marked_incrementally_ && FLAG_verify_heap) { 935 VerifyMarkbitsAreClean(); 936 } 937 #endif 938 } 939 940 941 void MarkCompactCollector::Finish() { 942 #ifdef DEBUG 943 ASSERT(state_ == SWEEP_SPACES || state_ == RELOCATE_OBJECTS); 944 state_ = IDLE; 945 #endif 946 // The stub cache is not traversed during GC; clear the cache to 947 // force lazy re-initialization of it. This must be done after the 948 // GC, because it relies on the new address of certain old space 949 // objects (empty string, illegal builtin). 950 isolate()->stub_cache()->Clear(); 951 952 if (have_code_to_deoptimize_) { 953 // Some code objects were marked for deoptimization during the GC. 954 Deoptimizer::DeoptimizeMarkedCode(isolate()); 955 have_code_to_deoptimize_ = false; 956 } 957 } 958 959 960 // ------------------------------------------------------------------------- 961 // Phase 1: tracing and marking live objects. 962 // before: all objects are in normal state. 963 // after: a live object's map pointer is marked as '00'. 964 965 // Marking all live objects in the heap as part of mark-sweep or mark-compact 966 // collection. Before marking, all objects are in their normal state. After 967 // marking, live objects' map pointers are marked indicating that the object 968 // has been found reachable. 969 // 970 // The marking algorithm is a (mostly) depth-first (because of possible stack 971 // overflow) traversal of the graph of objects reachable from the roots. It 972 // uses an explicit stack of pointers rather than recursion. The young 973 // generation's inactive ('from') space is used as a marking stack. The 974 // objects in the marking stack are the ones that have been reached and marked 975 // but their children have not yet been visited. 976 // 977 // The marking stack can overflow during traversal. In that case, we set an 978 // overflow flag. When the overflow flag is set, we continue marking objects 979 // reachable from the objects on the marking stack, but no longer push them on 980 // the marking stack. Instead, we mark them as both marked and overflowed. 981 // When the stack is in the overflowed state, objects marked as overflowed 982 // have been reached and marked but their children have not been visited yet. 983 // After emptying the marking stack, we clear the overflow flag and traverse 984 // the heap looking for objects marked as overflowed, push them on the stack, 985 // and continue with marking. This process repeats until all reachable 986 // objects have been marked. 987 988 void CodeFlusher::ProcessJSFunctionCandidates() { 989 Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); 990 Object* undefined = isolate_->heap()->undefined_value(); 991 992 JSFunction* candidate = jsfunction_candidates_head_; 993 JSFunction* next_candidate; 994 while (candidate != NULL) { 995 next_candidate = GetNextCandidate(candidate); 996 ClearNextCandidate(candidate, undefined); 997 998 SharedFunctionInfo* shared = candidate->shared(); 999 1000 Code* code = shared->code(); 1001 MarkBit code_mark = Marking::MarkBitFrom(code); 1002 if (!code_mark.Get()) { 1003 if (FLAG_trace_code_flushing && shared->is_compiled()) { 1004 PrintF("[code-flushing clears: "); 1005 shared->ShortPrint(); 1006 PrintF(" - age: %d]\n", code->GetAge()); 1007 } 1008 shared->set_code(lazy_compile); 1009 candidate->set_code(lazy_compile); 1010 } else { 1011 candidate->set_code(code); 1012 } 1013 1014 // We are in the middle of a GC cycle so the write barrier in the code 1015 // setter did not record the slot update and we have to do that manually. 1016 Address slot = candidate->address() + JSFunction::kCodeEntryOffset; 1017 Code* target = Code::cast(Code::GetObjectFromEntryAddress(slot)); 1018 isolate_->heap()->mark_compact_collector()-> 1019 RecordCodeEntrySlot(slot, target); 1020 1021 Object** shared_code_slot = 1022 HeapObject::RawField(shared, SharedFunctionInfo::kCodeOffset); 1023 isolate_->heap()->mark_compact_collector()-> 1024 RecordSlot(shared_code_slot, shared_code_slot, *shared_code_slot); 1025 1026 candidate = next_candidate; 1027 } 1028 1029 jsfunction_candidates_head_ = NULL; 1030 } 1031 1032 1033 void CodeFlusher::ProcessSharedFunctionInfoCandidates() { 1034 Code* lazy_compile = isolate_->builtins()->builtin(Builtins::kLazyCompile); 1035 1036 SharedFunctionInfo* candidate = shared_function_info_candidates_head_; 1037 SharedFunctionInfo* next_candidate; 1038 while (candidate != NULL) { 1039 next_candidate = GetNextCandidate(candidate); 1040 ClearNextCandidate(candidate); 1041 1042 Code* code = candidate->code(); 1043 MarkBit code_mark = Marking::MarkBitFrom(code); 1044 if (!code_mark.Get()) { 1045 if (FLAG_trace_code_flushing && candidate->is_compiled()) { 1046 PrintF("[code-flushing clears: "); 1047 candidate->ShortPrint(); 1048 PrintF(" - age: %d]\n", code->GetAge()); 1049 } 1050 candidate->set_code(lazy_compile); 1051 } 1052 1053 Object** code_slot = 1054 HeapObject::RawField(candidate, SharedFunctionInfo::kCodeOffset); 1055 isolate_->heap()->mark_compact_collector()-> 1056 RecordSlot(code_slot, code_slot, *code_slot); 1057 1058 candidate = next_candidate; 1059 } 1060 1061 shared_function_info_candidates_head_ = NULL; 1062 } 1063 1064 1065 void CodeFlusher::ProcessOptimizedCodeMaps() { 1066 static const int kEntriesStart = SharedFunctionInfo::kEntriesStart; 1067 static const int kEntryLength = SharedFunctionInfo::kEntryLength; 1068 static const int kContextOffset = 0; 1069 static const int kCodeOffset = 1; 1070 static const int kLiteralsOffset = 2; 1071 STATIC_ASSERT(kEntryLength == 3); 1072 1073 SharedFunctionInfo* holder = optimized_code_map_holder_head_; 1074 SharedFunctionInfo* next_holder; 1075 while (holder != NULL) { 1076 next_holder = GetNextCodeMap(holder); 1077 ClearNextCodeMap(holder); 1078 1079 FixedArray* code_map = FixedArray::cast(holder->optimized_code_map()); 1080 int new_length = kEntriesStart; 1081 int old_length = code_map->length(); 1082 for (int i = kEntriesStart; i < old_length; i += kEntryLength) { 1083 Code* code = Code::cast(code_map->get(i + kCodeOffset)); 1084 MarkBit code_mark = Marking::MarkBitFrom(code); 1085 if (!code_mark.Get()) { 1086 continue; 1087 } 1088 1089 // Update and record the context slot in the optimized code map. 1090 Object** context_slot = HeapObject::RawField(code_map, 1091 FixedArray::OffsetOfElementAt(new_length)); 1092 code_map->set(new_length++, code_map->get(i + kContextOffset)); 1093 ASSERT(Marking::IsBlack( 1094 Marking::MarkBitFrom(HeapObject::cast(*context_slot)))); 1095 isolate_->heap()->mark_compact_collector()-> 1096 RecordSlot(context_slot, context_slot, *context_slot); 1097 1098 // Update and record the code slot in the optimized code map. 1099 Object** code_slot = HeapObject::RawField(code_map, 1100 FixedArray::OffsetOfElementAt(new_length)); 1101 code_map->set(new_length++, code_map->get(i + kCodeOffset)); 1102 ASSERT(Marking::IsBlack( 1103 Marking::MarkBitFrom(HeapObject::cast(*code_slot)))); 1104 isolate_->heap()->mark_compact_collector()-> 1105 RecordSlot(code_slot, code_slot, *code_slot); 1106 1107 // Update and record the literals slot in the optimized code map. 1108 Object** literals_slot = HeapObject::RawField(code_map, 1109 FixedArray::OffsetOfElementAt(new_length)); 1110 code_map->set(new_length++, code_map->get(i + kLiteralsOffset)); 1111 ASSERT(Marking::IsBlack( 1112 Marking::MarkBitFrom(HeapObject::cast(*literals_slot)))); 1113 isolate_->heap()->mark_compact_collector()-> 1114 RecordSlot(literals_slot, literals_slot, *literals_slot); 1115 } 1116 1117 // Trim the optimized code map if entries have been removed. 1118 if (new_length < old_length) { 1119 holder->TrimOptimizedCodeMap(old_length - new_length); 1120 } 1121 1122 holder = next_holder; 1123 } 1124 1125 optimized_code_map_holder_head_ = NULL; 1126 } 1127 1128 1129 void CodeFlusher::EvictCandidate(SharedFunctionInfo* shared_info) { 1130 // Make sure previous flushing decisions are revisited. 1131 isolate_->heap()->incremental_marking()->RecordWrites(shared_info); 1132 1133 if (FLAG_trace_code_flushing) { 1134 PrintF("[code-flushing abandons function-info: "); 1135 shared_info->ShortPrint(); 1136 PrintF("]\n"); 1137 } 1138 1139 SharedFunctionInfo* candidate = shared_function_info_candidates_head_; 1140 SharedFunctionInfo* next_candidate; 1141 if (candidate == shared_info) { 1142 next_candidate = GetNextCandidate(shared_info); 1143 shared_function_info_candidates_head_ = next_candidate; 1144 ClearNextCandidate(shared_info); 1145 } else { 1146 while (candidate != NULL) { 1147 next_candidate = GetNextCandidate(candidate); 1148 1149 if (next_candidate == shared_info) { 1150 next_candidate = GetNextCandidate(shared_info); 1151 SetNextCandidate(candidate, next_candidate); 1152 ClearNextCandidate(shared_info); 1153 break; 1154 } 1155 1156 candidate = next_candidate; 1157 } 1158 } 1159 } 1160 1161 1162 void CodeFlusher::EvictCandidate(JSFunction* function) { 1163 ASSERT(!function->next_function_link()->IsUndefined()); 1164 Object* undefined = isolate_->heap()->undefined_value(); 1165 1166 // Make sure previous flushing decisions are revisited. 1167 isolate_->heap()->incremental_marking()->RecordWrites(function); 1168 isolate_->heap()->incremental_marking()->RecordWrites(function->shared()); 1169 1170 if (FLAG_trace_code_flushing) { 1171 PrintF("[code-flushing abandons closure: "); 1172 function->shared()->ShortPrint(); 1173 PrintF("]\n"); 1174 } 1175 1176 JSFunction* candidate = jsfunction_candidates_head_; 1177 JSFunction* next_candidate; 1178 if (candidate == function) { 1179 next_candidate = GetNextCandidate(function); 1180 jsfunction_candidates_head_ = next_candidate; 1181 ClearNextCandidate(function, undefined); 1182 } else { 1183 while (candidate != NULL) { 1184 next_candidate = GetNextCandidate(candidate); 1185 1186 if (next_candidate == function) { 1187 next_candidate = GetNextCandidate(function); 1188 SetNextCandidate(candidate, next_candidate); 1189 ClearNextCandidate(function, undefined); 1190 break; 1191 } 1192 1193 candidate = next_candidate; 1194 } 1195 } 1196 } 1197 1198 1199 void CodeFlusher::EvictOptimizedCodeMap(SharedFunctionInfo* code_map_holder) { 1200 ASSERT(!FixedArray::cast(code_map_holder->optimized_code_map())-> 1201 get(SharedFunctionInfo::kNextMapIndex)->IsUndefined()); 1202 1203 // Make sure previous flushing decisions are revisited. 1204 isolate_->heap()->incremental_marking()->RecordWrites(code_map_holder); 1205 1206 if (FLAG_trace_code_flushing) { 1207 PrintF("[code-flushing abandons code-map: "); 1208 code_map_holder->ShortPrint(); 1209 PrintF("]\n"); 1210 } 1211 1212 SharedFunctionInfo* holder = optimized_code_map_holder_head_; 1213 SharedFunctionInfo* next_holder; 1214 if (holder == code_map_holder) { 1215 next_holder = GetNextCodeMap(code_map_holder); 1216 optimized_code_map_holder_head_ = next_holder; 1217 ClearNextCodeMap(code_map_holder); 1218 } else { 1219 while (holder != NULL) { 1220 next_holder = GetNextCodeMap(holder); 1221 1222 if (next_holder == code_map_holder) { 1223 next_holder = GetNextCodeMap(code_map_holder); 1224 SetNextCodeMap(holder, next_holder); 1225 ClearNextCodeMap(code_map_holder); 1226 break; 1227 } 1228 1229 holder = next_holder; 1230 } 1231 } 1232 } 1233 1234 1235 void CodeFlusher::EvictJSFunctionCandidates() { 1236 JSFunction* candidate = jsfunction_candidates_head_; 1237 JSFunction* next_candidate; 1238 while (candidate != NULL) { 1239 next_candidate = GetNextCandidate(candidate); 1240 EvictCandidate(candidate); 1241 candidate = next_candidate; 1242 } 1243 ASSERT(jsfunction_candidates_head_ == NULL); 1244 } 1245 1246 1247 void CodeFlusher::EvictSharedFunctionInfoCandidates() { 1248 SharedFunctionInfo* candidate = shared_function_info_candidates_head_; 1249 SharedFunctionInfo* next_candidate; 1250 while (candidate != NULL) { 1251 next_candidate = GetNextCandidate(candidate); 1252 EvictCandidate(candidate); 1253 candidate = next_candidate; 1254 } 1255 ASSERT(shared_function_info_candidates_head_ == NULL); 1256 } 1257 1258 1259 void CodeFlusher::EvictOptimizedCodeMaps() { 1260 SharedFunctionInfo* holder = optimized_code_map_holder_head_; 1261 SharedFunctionInfo* next_holder; 1262 while (holder != NULL) { 1263 next_holder = GetNextCodeMap(holder); 1264 EvictOptimizedCodeMap(holder); 1265 holder = next_holder; 1266 } 1267 ASSERT(optimized_code_map_holder_head_ == NULL); 1268 } 1269 1270 1271 void CodeFlusher::IteratePointersToFromSpace(ObjectVisitor* v) { 1272 Heap* heap = isolate_->heap(); 1273 1274 JSFunction** slot = &jsfunction_candidates_head_; 1275 JSFunction* candidate = jsfunction_candidates_head_; 1276 while (candidate != NULL) { 1277 if (heap->InFromSpace(candidate)) { 1278 v->VisitPointer(reinterpret_cast<Object**>(slot)); 1279 } 1280 candidate = GetNextCandidate(*slot); 1281 slot = GetNextCandidateSlot(*slot); 1282 } 1283 } 1284 1285 1286 MarkCompactCollector::~MarkCompactCollector() { 1287 if (code_flusher_ != NULL) { 1288 delete code_flusher_; 1289 code_flusher_ = NULL; 1290 } 1291 } 1292 1293 1294 static inline HeapObject* ShortCircuitConsString(Object** p) { 1295 // Optimization: If the heap object pointed to by p is a non-internalized 1296 // cons string whose right substring is HEAP->empty_string, update 1297 // it in place to its left substring. Return the updated value. 1298 // 1299 // Here we assume that if we change *p, we replace it with a heap object 1300 // (i.e., the left substring of a cons string is always a heap object). 1301 // 1302 // The check performed is: 1303 // object->IsConsString() && !object->IsInternalizedString() && 1304 // (ConsString::cast(object)->second() == HEAP->empty_string()) 1305 // except the maps for the object and its possible substrings might be 1306 // marked. 1307 HeapObject* object = HeapObject::cast(*p); 1308 if (!FLAG_clever_optimizations) return object; 1309 Map* map = object->map(); 1310 InstanceType type = map->instance_type(); 1311 if ((type & kShortcutTypeMask) != kShortcutTypeTag) return object; 1312 1313 Object* second = reinterpret_cast<ConsString*>(object)->second(); 1314 Heap* heap = map->GetHeap(); 1315 if (second != heap->empty_string()) { 1316 return object; 1317 } 1318 1319 // Since we don't have the object's start, it is impossible to update the 1320 // page dirty marks. Therefore, we only replace the string with its left 1321 // substring when page dirty marks do not change. 1322 Object* first = reinterpret_cast<ConsString*>(object)->first(); 1323 if (!heap->InNewSpace(object) && heap->InNewSpace(first)) return object; 1324 1325 *p = first; 1326 return HeapObject::cast(first); 1327 } 1328 1329 1330 class MarkCompactMarkingVisitor 1331 : public StaticMarkingVisitor<MarkCompactMarkingVisitor> { 1332 public: 1333 static void ObjectStatsVisitBase(StaticVisitorBase::VisitorId id, 1334 Map* map, HeapObject* obj); 1335 1336 static void ObjectStatsCountFixedArray( 1337 FixedArrayBase* fixed_array, 1338 FixedArraySubInstanceType fast_type, 1339 FixedArraySubInstanceType dictionary_type); 1340 1341 template<MarkCompactMarkingVisitor::VisitorId id> 1342 class ObjectStatsTracker { 1343 public: 1344 static inline void Visit(Map* map, HeapObject* obj); 1345 }; 1346 1347 static void Initialize(); 1348 1349 INLINE(static void VisitPointer(Heap* heap, Object** p)) { 1350 MarkObjectByPointer(heap->mark_compact_collector(), p, p); 1351 } 1352 1353 INLINE(static void VisitPointers(Heap* heap, Object** start, Object** end)) { 1354 // Mark all objects pointed to in [start, end). 1355 const int kMinRangeForMarkingRecursion = 64; 1356 if (end - start >= kMinRangeForMarkingRecursion) { 1357 if (VisitUnmarkedObjects(heap, start, end)) return; 1358 // We are close to a stack overflow, so just mark the objects. 1359 } 1360 MarkCompactCollector* collector = heap->mark_compact_collector(); 1361 for (Object** p = start; p < end; p++) { 1362 MarkObjectByPointer(collector, start, p); 1363 } 1364 } 1365 1366 // Marks the object black and pushes it on the marking stack. 1367 INLINE(static void MarkObject(Heap* heap, HeapObject* object)) { 1368 MarkBit mark = Marking::MarkBitFrom(object); 1369 heap->mark_compact_collector()->MarkObject(object, mark); 1370 } 1371 1372 // Marks the object black without pushing it on the marking stack. 1373 // Returns true if object needed marking and false otherwise. 1374 INLINE(static bool MarkObjectWithoutPush(Heap* heap, HeapObject* object)) { 1375 MarkBit mark_bit = Marking::MarkBitFrom(object); 1376 if (!mark_bit.Get()) { 1377 heap->mark_compact_collector()->SetMark(object, mark_bit); 1378 return true; 1379 } 1380 return false; 1381 } 1382 1383 // Mark object pointed to by p. 1384 INLINE(static void MarkObjectByPointer(MarkCompactCollector* collector, 1385 Object** anchor_slot, 1386 Object** p)) { 1387 if (!(*p)->IsHeapObject()) return; 1388 HeapObject* object = ShortCircuitConsString(p); 1389 collector->RecordSlot(anchor_slot, p, object); 1390 MarkBit mark = Marking::MarkBitFrom(object); 1391 collector->MarkObject(object, mark); 1392 } 1393 1394 1395 // Visit an unmarked object. 1396 INLINE(static void VisitUnmarkedObject(MarkCompactCollector* collector, 1397 HeapObject* obj)) { 1398 #ifdef DEBUG 1399 ASSERT(collector->heap()->Contains(obj)); 1400 ASSERT(!collector->heap()->mark_compact_collector()->IsMarked(obj)); 1401 #endif 1402 Map* map = obj->map(); 1403 Heap* heap = obj->GetHeap(); 1404 MarkBit mark = Marking::MarkBitFrom(obj); 1405 heap->mark_compact_collector()->SetMark(obj, mark); 1406 // Mark the map pointer and the body. 1407 MarkBit map_mark = Marking::MarkBitFrom(map); 1408 heap->mark_compact_collector()->MarkObject(map, map_mark); 1409 IterateBody(map, obj); 1410 } 1411 1412 // Visit all unmarked objects pointed to by [start, end). 1413 // Returns false if the operation fails (lack of stack space). 1414 INLINE(static bool VisitUnmarkedObjects(Heap* heap, 1415 Object** start, 1416 Object** end)) { 1417 // Return false is we are close to the stack limit. 1418 StackLimitCheck check(heap->isolate()); 1419 if (check.HasOverflowed()) return false; 1420 1421 MarkCompactCollector* collector = heap->mark_compact_collector(); 1422 // Visit the unmarked objects. 1423 for (Object** p = start; p < end; p++) { 1424 Object* o = *p; 1425 if (!o->IsHeapObject()) continue; 1426 collector->RecordSlot(start, p, o); 1427 HeapObject* obj = HeapObject::cast(o); 1428 MarkBit mark = Marking::MarkBitFrom(obj); 1429 if (mark.Get()) continue; 1430 VisitUnmarkedObject(collector, obj); 1431 } 1432 return true; 1433 } 1434 1435 INLINE(static void BeforeVisitingSharedFunctionInfo(HeapObject* object)) { 1436 SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); 1437 shared->BeforeVisitingPointers(); 1438 } 1439 1440 static void VisitWeakCollection(Map* map, HeapObject* object) { 1441 MarkCompactCollector* collector = map->GetHeap()->mark_compact_collector(); 1442 JSWeakCollection* weak_collection = 1443 reinterpret_cast<JSWeakCollection*>(object); 1444 1445 // Enqueue weak map in linked list of encountered weak maps. 1446 if (weak_collection->next() == Smi::FromInt(0)) { 1447 weak_collection->set_next(collector->encountered_weak_collections()); 1448 collector->set_encountered_weak_collections(weak_collection); 1449 } 1450 1451 // Skip visiting the backing hash table containing the mappings. 1452 int object_size = JSWeakCollection::BodyDescriptor::SizeOf(map, object); 1453 BodyVisitorBase<MarkCompactMarkingVisitor>::IteratePointers( 1454 map->GetHeap(), 1455 object, 1456 JSWeakCollection::BodyDescriptor::kStartOffset, 1457 JSWeakCollection::kTableOffset); 1458 BodyVisitorBase<MarkCompactMarkingVisitor>::IteratePointers( 1459 map->GetHeap(), 1460 object, 1461 JSWeakCollection::kTableOffset + kPointerSize, 1462 object_size); 1463 1464 // Mark the backing hash table without pushing it on the marking stack. 1465 Object* table_object = weak_collection->table(); 1466 if (!table_object->IsHashTable()) return; 1467 WeakHashTable* table = WeakHashTable::cast(table_object); 1468 Object** table_slot = 1469 HeapObject::RawField(weak_collection, JSWeakCollection::kTableOffset); 1470 MarkBit table_mark = Marking::MarkBitFrom(table); 1471 collector->RecordSlot(table_slot, table_slot, table); 1472 if (!table_mark.Get()) collector->SetMark(table, table_mark); 1473 // Recording the map slot can be skipped, because maps are not compacted. 1474 collector->MarkObject(table->map(), Marking::MarkBitFrom(table->map())); 1475 ASSERT(MarkCompactCollector::IsMarked(table->map())); 1476 } 1477 1478 private: 1479 template<int id> 1480 static inline void TrackObjectStatsAndVisit(Map* map, HeapObject* obj); 1481 1482 // Code flushing support. 1483 1484 static const int kRegExpCodeThreshold = 5; 1485 1486 static void UpdateRegExpCodeAgeAndFlush(Heap* heap, 1487 JSRegExp* re, 1488 bool is_ascii) { 1489 // Make sure that the fixed array is in fact initialized on the RegExp. 1490 // We could potentially trigger a GC when initializing the RegExp. 1491 if (HeapObject::cast(re->data())->map()->instance_type() != 1492 FIXED_ARRAY_TYPE) return; 1493 1494 // Make sure this is a RegExp that actually contains code. 1495 if (re->TypeTag() != JSRegExp::IRREGEXP) return; 1496 1497 Object* code = re->DataAt(JSRegExp::code_index(is_ascii)); 1498 if (!code->IsSmi() && 1499 HeapObject::cast(code)->map()->instance_type() == CODE_TYPE) { 1500 // Save a copy that can be reinstated if we need the code again. 1501 re->SetDataAt(JSRegExp::saved_code_index(is_ascii), code); 1502 1503 // Saving a copy might create a pointer into compaction candidate 1504 // that was not observed by marker. This might happen if JSRegExp data 1505 // was marked through the compilation cache before marker reached JSRegExp 1506 // object. 1507 FixedArray* data = FixedArray::cast(re->data()); 1508 Object** slot = data->data_start() + JSRegExp::saved_code_index(is_ascii); 1509 heap->mark_compact_collector()-> 1510 RecordSlot(slot, slot, code); 1511 1512 // Set a number in the 0-255 range to guarantee no smi overflow. 1513 re->SetDataAt(JSRegExp::code_index(is_ascii), 1514 Smi::FromInt(heap->sweep_generation() & 0xff)); 1515 } else if (code->IsSmi()) { 1516 int value = Smi::cast(code)->value(); 1517 // The regexp has not been compiled yet or there was a compilation error. 1518 if (value == JSRegExp::kUninitializedValue || 1519 value == JSRegExp::kCompilationErrorValue) { 1520 return; 1521 } 1522 1523 // Check if we should flush now. 1524 if (value == ((heap->sweep_generation() - kRegExpCodeThreshold) & 0xff)) { 1525 re->SetDataAt(JSRegExp::code_index(is_ascii), 1526 Smi::FromInt(JSRegExp::kUninitializedValue)); 1527 re->SetDataAt(JSRegExp::saved_code_index(is_ascii), 1528 Smi::FromInt(JSRegExp::kUninitializedValue)); 1529 } 1530 } 1531 } 1532 1533 1534 // Works by setting the current sweep_generation (as a smi) in the 1535 // code object place in the data array of the RegExp and keeps a copy 1536 // around that can be reinstated if we reuse the RegExp before flushing. 1537 // If we did not use the code for kRegExpCodeThreshold mark sweep GCs 1538 // we flush the code. 1539 static void VisitRegExpAndFlushCode(Map* map, HeapObject* object) { 1540 Heap* heap = map->GetHeap(); 1541 MarkCompactCollector* collector = heap->mark_compact_collector(); 1542 if (!collector->is_code_flushing_enabled()) { 1543 VisitJSRegExp(map, object); 1544 return; 1545 } 1546 JSRegExp* re = reinterpret_cast<JSRegExp*>(object); 1547 // Flush code or set age on both ASCII and two byte code. 1548 UpdateRegExpCodeAgeAndFlush(heap, re, true); 1549 UpdateRegExpCodeAgeAndFlush(heap, re, false); 1550 // Visit the fields of the RegExp, including the updated FixedArray. 1551 VisitJSRegExp(map, object); 1552 } 1553 1554 static VisitorDispatchTable<Callback> non_count_table_; 1555 }; 1556 1557 1558 void MarkCompactMarkingVisitor::ObjectStatsCountFixedArray( 1559 FixedArrayBase* fixed_array, 1560 FixedArraySubInstanceType fast_type, 1561 FixedArraySubInstanceType dictionary_type) { 1562 Heap* heap = fixed_array->map()->GetHeap(); 1563 if (fixed_array->map() != heap->fixed_cow_array_map() && 1564 fixed_array->map() != heap->fixed_double_array_map() && 1565 fixed_array != heap->empty_fixed_array()) { 1566 if (fixed_array->IsDictionary()) { 1567 heap->RecordFixedArraySubTypeStats(dictionary_type, 1568 fixed_array->Size()); 1569 } else { 1570 heap->RecordFixedArraySubTypeStats(fast_type, 1571 fixed_array->Size()); 1572 } 1573 } 1574 } 1575 1576 1577 void MarkCompactMarkingVisitor::ObjectStatsVisitBase( 1578 MarkCompactMarkingVisitor::VisitorId id, Map* map, HeapObject* obj) { 1579 Heap* heap = map->GetHeap(); 1580 int object_size = obj->Size(); 1581 heap->RecordObjectStats(map->instance_type(), object_size); 1582 non_count_table_.GetVisitorById(id)(map, obj); 1583 if (obj->IsJSObject()) { 1584 JSObject* object = JSObject::cast(obj); 1585 ObjectStatsCountFixedArray(object->elements(), 1586 DICTIONARY_ELEMENTS_SUB_TYPE, 1587 FAST_ELEMENTS_SUB_TYPE); 1588 ObjectStatsCountFixedArray(object->properties(), 1589 DICTIONARY_PROPERTIES_SUB_TYPE, 1590 FAST_PROPERTIES_SUB_TYPE); 1591 } 1592 } 1593 1594 1595 template<MarkCompactMarkingVisitor::VisitorId id> 1596 void MarkCompactMarkingVisitor::ObjectStatsTracker<id>::Visit( 1597 Map* map, HeapObject* obj) { 1598 ObjectStatsVisitBase(id, map, obj); 1599 } 1600 1601 1602 template<> 1603 class MarkCompactMarkingVisitor::ObjectStatsTracker< 1604 MarkCompactMarkingVisitor::kVisitMap> { 1605 public: 1606 static inline void Visit(Map* map, HeapObject* obj) { 1607 Heap* heap = map->GetHeap(); 1608 Map* map_obj = Map::cast(obj); 1609 ASSERT(map->instance_type() == MAP_TYPE); 1610 DescriptorArray* array = map_obj->instance_descriptors(); 1611 if (map_obj->owns_descriptors() && 1612 array != heap->empty_descriptor_array()) { 1613 int fixed_array_size = array->Size(); 1614 heap->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE, 1615 fixed_array_size); 1616 } 1617 if (map_obj->HasTransitionArray()) { 1618 int fixed_array_size = map_obj->transitions()->Size(); 1619 heap->RecordFixedArraySubTypeStats(TRANSITION_ARRAY_SUB_TYPE, 1620 fixed_array_size); 1621 } 1622 if (map_obj->has_code_cache()) { 1623 CodeCache* cache = CodeCache::cast(map_obj->code_cache()); 1624 heap->RecordFixedArraySubTypeStats(MAP_CODE_CACHE_SUB_TYPE, 1625 cache->default_cache()->Size()); 1626 if (!cache->normal_type_cache()->IsUndefined()) { 1627 heap->RecordFixedArraySubTypeStats( 1628 MAP_CODE_CACHE_SUB_TYPE, 1629 FixedArray::cast(cache->normal_type_cache())->Size()); 1630 } 1631 } 1632 ObjectStatsVisitBase(kVisitMap, map, obj); 1633 } 1634 }; 1635 1636 1637 template<> 1638 class MarkCompactMarkingVisitor::ObjectStatsTracker< 1639 MarkCompactMarkingVisitor::kVisitCode> { 1640 public: 1641 static inline void Visit(Map* map, HeapObject* obj) { 1642 Heap* heap = map->GetHeap(); 1643 int object_size = obj->Size(); 1644 ASSERT(map->instance_type() == CODE_TYPE); 1645 Code* code_obj = Code::cast(obj); 1646 heap->RecordCodeSubTypeStats(code_obj->kind(), code_obj->GetRawAge(), 1647 object_size); 1648 ObjectStatsVisitBase(kVisitCode, map, obj); 1649 } 1650 }; 1651 1652 1653 template<> 1654 class MarkCompactMarkingVisitor::ObjectStatsTracker< 1655 MarkCompactMarkingVisitor::kVisitSharedFunctionInfo> { 1656 public: 1657 static inline void Visit(Map* map, HeapObject* obj) { 1658 Heap* heap = map->GetHeap(); 1659 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj); 1660 if (sfi->scope_info() != heap->empty_fixed_array()) { 1661 heap->RecordFixedArraySubTypeStats( 1662 SCOPE_INFO_SUB_TYPE, 1663 FixedArray::cast(sfi->scope_info())->Size()); 1664 } 1665 ObjectStatsVisitBase(kVisitSharedFunctionInfo, map, obj); 1666 } 1667 }; 1668 1669 1670 template<> 1671 class MarkCompactMarkingVisitor::ObjectStatsTracker< 1672 MarkCompactMarkingVisitor::kVisitFixedArray> { 1673 public: 1674 static inline void Visit(Map* map, HeapObject* obj) { 1675 Heap* heap = map->GetHeap(); 1676 FixedArray* fixed_array = FixedArray::cast(obj); 1677 if (fixed_array == heap->string_table()) { 1678 heap->RecordFixedArraySubTypeStats( 1679 STRING_TABLE_SUB_TYPE, 1680 fixed_array->Size()); 1681 } 1682 ObjectStatsVisitBase(kVisitFixedArray, map, obj); 1683 } 1684 }; 1685 1686 1687 void MarkCompactMarkingVisitor::Initialize() { 1688 StaticMarkingVisitor<MarkCompactMarkingVisitor>::Initialize(); 1689 1690 table_.Register(kVisitJSRegExp, 1691 &VisitRegExpAndFlushCode); 1692 1693 if (FLAG_track_gc_object_stats) { 1694 // Copy the visitor table to make call-through possible. 1695 non_count_table_.CopyFrom(&table_); 1696 #define VISITOR_ID_COUNT_FUNCTION(id) \ 1697 table_.Register(kVisit##id, ObjectStatsTracker<kVisit##id>::Visit); 1698 VISITOR_ID_LIST(VISITOR_ID_COUNT_FUNCTION) 1699 #undef VISITOR_ID_COUNT_FUNCTION 1700 } 1701 } 1702 1703 1704 VisitorDispatchTable<MarkCompactMarkingVisitor::Callback> 1705 MarkCompactMarkingVisitor::non_count_table_; 1706 1707 1708 class CodeMarkingVisitor : public ThreadVisitor { 1709 public: 1710 explicit CodeMarkingVisitor(MarkCompactCollector* collector) 1711 : collector_(collector) {} 1712 1713 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { 1714 collector_->PrepareThreadForCodeFlushing(isolate, top); 1715 } 1716 1717 private: 1718 MarkCompactCollector* collector_; 1719 }; 1720 1721 1722 class SharedFunctionInfoMarkingVisitor : public ObjectVisitor { 1723 public: 1724 explicit SharedFunctionInfoMarkingVisitor(MarkCompactCollector* collector) 1725 : collector_(collector) {} 1726 1727 void VisitPointers(Object** start, Object** end) { 1728 for (Object** p = start; p < end; p++) VisitPointer(p); 1729 } 1730 1731 void VisitPointer(Object** slot) { 1732 Object* obj = *slot; 1733 if (obj->IsSharedFunctionInfo()) { 1734 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(obj); 1735 MarkBit shared_mark = Marking::MarkBitFrom(shared); 1736 MarkBit code_mark = Marking::MarkBitFrom(shared->code()); 1737 collector_->MarkObject(shared->code(), code_mark); 1738 collector_->MarkObject(shared, shared_mark); 1739 } 1740 } 1741 1742 private: 1743 MarkCompactCollector* collector_; 1744 }; 1745 1746 1747 void MarkCompactCollector::PrepareThreadForCodeFlushing(Isolate* isolate, 1748 ThreadLocalTop* top) { 1749 for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) { 1750 // Note: for the frame that has a pending lazy deoptimization 1751 // StackFrame::unchecked_code will return a non-optimized code object for 1752 // the outermost function and StackFrame::LookupCode will return 1753 // actual optimized code object. 1754 StackFrame* frame = it.frame(); 1755 Code* code = frame->unchecked_code(); 1756 MarkBit code_mark = Marking::MarkBitFrom(code); 1757 MarkObject(code, code_mark); 1758 if (frame->is_optimized()) { 1759 MarkCompactMarkingVisitor::MarkInlinedFunctionsCode(heap(), 1760 frame->LookupCode()); 1761 } 1762 } 1763 } 1764 1765 1766 void MarkCompactCollector::PrepareForCodeFlushing() { 1767 // Enable code flushing for non-incremental cycles. 1768 if (FLAG_flush_code && !FLAG_flush_code_incrementally) { 1769 EnableCodeFlushing(!was_marked_incrementally_); 1770 } 1771 1772 // If code flushing is disabled, there is no need to prepare for it. 1773 if (!is_code_flushing_enabled()) return; 1774 1775 // Ensure that empty descriptor array is marked. Method MarkDescriptorArray 1776 // relies on it being marked before any other descriptor array. 1777 HeapObject* descriptor_array = heap()->empty_descriptor_array(); 1778 MarkBit descriptor_array_mark = Marking::MarkBitFrom(descriptor_array); 1779 MarkObject(descriptor_array, descriptor_array_mark); 1780 1781 // Make sure we are not referencing the code from the stack. 1782 ASSERT(this == heap()->mark_compact_collector()); 1783 PrepareThreadForCodeFlushing(heap()->isolate(), 1784 heap()->isolate()->thread_local_top()); 1785 1786 // Iterate the archived stacks in all threads to check if 1787 // the code is referenced. 1788 CodeMarkingVisitor code_marking_visitor(this); 1789 heap()->isolate()->thread_manager()->IterateArchivedThreads( 1790 &code_marking_visitor); 1791 1792 SharedFunctionInfoMarkingVisitor visitor(this); 1793 heap()->isolate()->compilation_cache()->IterateFunctions(&visitor); 1794 heap()->isolate()->handle_scope_implementer()->Iterate(&visitor); 1795 1796 ProcessMarkingDeque(); 1797 } 1798 1799 1800 // Visitor class for marking heap roots. 1801 class RootMarkingVisitor : public ObjectVisitor { 1802 public: 1803 explicit RootMarkingVisitor(Heap* heap) 1804 : collector_(heap->mark_compact_collector()) { } 1805 1806 void VisitPointer(Object** p) { 1807 MarkObjectByPointer(p); 1808 } 1809 1810 void VisitPointers(Object** start, Object** end) { 1811 for (Object** p = start; p < end; p++) MarkObjectByPointer(p); 1812 } 1813 1814 private: 1815 void MarkObjectByPointer(Object** p) { 1816 if (!(*p)->IsHeapObject()) return; 1817 1818 // Replace flat cons strings in place. 1819 HeapObject* object = ShortCircuitConsString(p); 1820 MarkBit mark_bit = Marking::MarkBitFrom(object); 1821 if (mark_bit.Get()) return; 1822 1823 Map* map = object->map(); 1824 // Mark the object. 1825 collector_->SetMark(object, mark_bit); 1826 1827 // Mark the map pointer and body, and push them on the marking stack. 1828 MarkBit map_mark = Marking::MarkBitFrom(map); 1829 collector_->MarkObject(map, map_mark); 1830 MarkCompactMarkingVisitor::IterateBody(map, object); 1831 1832 // Mark all the objects reachable from the map and body. May leave 1833 // overflowed objects in the heap. 1834 collector_->EmptyMarkingDeque(); 1835 } 1836 1837 MarkCompactCollector* collector_; 1838 }; 1839 1840 1841 // Helper class for pruning the string table. 1842 class StringTableCleaner : public ObjectVisitor { 1843 public: 1844 explicit StringTableCleaner(Heap* heap) 1845 : heap_(heap), pointers_removed_(0) { } 1846 1847 virtual void VisitPointers(Object** start, Object** end) { 1848 // Visit all HeapObject pointers in [start, end). 1849 for (Object** p = start; p < end; p++) { 1850 Object* o = *p; 1851 if (o->IsHeapObject() && 1852 !Marking::MarkBitFrom(HeapObject::cast(o)).Get()) { 1853 // Check if the internalized string being pruned is external. We need to 1854 // delete the associated external data as this string is going away. 1855 1856 // Since no objects have yet been moved we can safely access the map of 1857 // the object. 1858 if (o->IsExternalString()) { 1859 heap_->FinalizeExternalString(String::cast(*p)); 1860 } 1861 // Set the entry to the_hole_value (as deleted). 1862 *p = heap_->the_hole_value(); 1863 pointers_removed_++; 1864 } 1865 } 1866 } 1867 1868 int PointersRemoved() { 1869 return pointers_removed_; 1870 } 1871 1872 private: 1873 Heap* heap_; 1874 int pointers_removed_; 1875 }; 1876 1877 1878 // Implementation of WeakObjectRetainer for mark compact GCs. All marked objects 1879 // are retained. 1880 class MarkCompactWeakObjectRetainer : public WeakObjectRetainer { 1881 public: 1882 virtual Object* RetainAs(Object* object) { 1883 if (Marking::MarkBitFrom(HeapObject::cast(object)).Get()) { 1884 return object; 1885 } else if (object->IsAllocationSite() && 1886 !(AllocationSite::cast(object)->IsZombie())) { 1887 // "dead" AllocationSites need to live long enough for a traversal of new 1888 // space. These sites get a one-time reprieve. 1889 AllocationSite* site = AllocationSite::cast(object); 1890 site->MarkZombie(); 1891 site->GetHeap()->mark_compact_collector()->MarkAllocationSite(site); 1892 return object; 1893 } else { 1894 return NULL; 1895 } 1896 } 1897 }; 1898 1899 1900 // Fill the marking stack with overflowed objects returned by the given 1901 // iterator. Stop when the marking stack is filled or the end of the space 1902 // is reached, whichever comes first. 1903 template<class T> 1904 static void DiscoverGreyObjectsWithIterator(Heap* heap, 1905 MarkingDeque* marking_deque, 1906 T* it) { 1907 // The caller should ensure that the marking stack is initially not full, 1908 // so that we don't waste effort pointlessly scanning for objects. 1909 ASSERT(!marking_deque->IsFull()); 1910 1911 Map* filler_map = heap->one_pointer_filler_map(); 1912 for (HeapObject* object = it->Next(); 1913 object != NULL; 1914 object = it->Next()) { 1915 MarkBit markbit = Marking::MarkBitFrom(object); 1916 if ((object->map() != filler_map) && Marking::IsGrey(markbit)) { 1917 Marking::GreyToBlack(markbit); 1918 MemoryChunk::IncrementLiveBytesFromGC(object->address(), object->Size()); 1919 marking_deque->PushBlack(object); 1920 if (marking_deque->IsFull()) return; 1921 } 1922 } 1923 } 1924 1925 1926 static inline int MarkWordToObjectStarts(uint32_t mark_bits, int* starts); 1927 1928 1929 static void DiscoverGreyObjectsOnPage(MarkingDeque* marking_deque, 1930 MemoryChunk* p) { 1931 ASSERT(!marking_deque->IsFull()); 1932 ASSERT(strcmp(Marking::kWhiteBitPattern, "00") == 0); 1933 ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0); 1934 ASSERT(strcmp(Marking::kGreyBitPattern, "11") == 0); 1935 ASSERT(strcmp(Marking::kImpossibleBitPattern, "01") == 0); 1936 1937 for (MarkBitCellIterator it(p); !it.Done(); it.Advance()) { 1938 Address cell_base = it.CurrentCellBase(); 1939 MarkBit::CellType* cell = it.CurrentCell(); 1940 1941 const MarkBit::CellType current_cell = *cell; 1942 if (current_cell == 0) continue; 1943 1944 MarkBit::CellType grey_objects; 1945 if (it.HasNext()) { 1946 const MarkBit::CellType next_cell = *(cell+1); 1947 grey_objects = current_cell & 1948 ((current_cell >> 1) | (next_cell << (Bitmap::kBitsPerCell - 1))); 1949 } else { 1950 grey_objects = current_cell & (current_cell >> 1); 1951 } 1952 1953 int offset = 0; 1954 while (grey_objects != 0) { 1955 int trailing_zeros = CompilerIntrinsics::CountTrailingZeros(grey_objects); 1956 grey_objects >>= trailing_zeros; 1957 offset += trailing_zeros; 1958 MarkBit markbit(cell, 1 << offset, false); 1959 ASSERT(Marking::IsGrey(markbit)); 1960 Marking::GreyToBlack(markbit); 1961 Address addr = cell_base + offset * kPointerSize; 1962 HeapObject* object = HeapObject::FromAddress(addr); 1963 MemoryChunk::IncrementLiveBytesFromGC(object->address(), object->Size()); 1964 marking_deque->PushBlack(object); 1965 if (marking_deque->IsFull()) return; 1966 offset += 2; 1967 grey_objects >>= 2; 1968 } 1969 1970 grey_objects >>= (Bitmap::kBitsPerCell - 1); 1971 } 1972 } 1973 1974 1975 int MarkCompactCollector::DiscoverAndPromoteBlackObjectsOnPage( 1976 NewSpace* new_space, 1977 NewSpacePage* p) { 1978 ASSERT(strcmp(Marking::kWhiteBitPattern, "00") == 0); 1979 ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0); 1980 ASSERT(strcmp(Marking::kGreyBitPattern, "11") == 0); 1981 ASSERT(strcmp(Marking::kImpossibleBitPattern, "01") == 0); 1982 1983 MarkBit::CellType* cells = p->markbits()->cells(); 1984 int survivors_size = 0; 1985 1986 for (MarkBitCellIterator it(p); !it.Done(); it.Advance()) { 1987 Address cell_base = it.CurrentCellBase(); 1988 MarkBit::CellType* cell = it.CurrentCell(); 1989 1990 MarkBit::CellType current_cell = *cell; 1991 if (current_cell == 0) continue; 1992 1993 int offset = 0; 1994 while (current_cell != 0) { 1995 int trailing_zeros = CompilerIntrinsics::CountTrailingZeros(current_cell); 1996 current_cell >>= trailing_zeros; 1997 offset += trailing_zeros; 1998 Address address = cell_base + offset * kPointerSize; 1999 HeapObject* object = HeapObject::FromAddress(address); 2000 2001 int size = object->Size(); 2002 survivors_size += size; 2003 2004 Heap::UpdateAllocationSiteFeedback(object); 2005 2006 offset++; 2007 current_cell >>= 1; 2008 // Aggressively promote young survivors to the old space. 2009 if (TryPromoteObject(object, size)) { 2010 continue; 2011 } 2012 2013 // Promotion failed. Just migrate object to another semispace. 2014 MaybeObject* allocation = new_space->AllocateRaw(size); 2015 if (allocation->IsFailure()) { 2016 if (!new_space->AddFreshPage()) { 2017 // Shouldn't happen. We are sweeping linearly, and to-space 2018 // has the same number of pages as from-space, so there is 2019 // always room. 2020 UNREACHABLE(); 2021 } 2022 allocation = new_space->AllocateRaw(size); 2023 ASSERT(!allocation->IsFailure()); 2024 } 2025 Object* target = allocation->ToObjectUnchecked(); 2026 2027 MigrateObject(HeapObject::cast(target)->address(), 2028 object->address(), 2029 size, 2030 NEW_SPACE); 2031 } 2032 *cells = 0; 2033 } 2034 return survivors_size; 2035 } 2036 2037 2038 static void DiscoverGreyObjectsInSpace(Heap* heap, 2039 MarkingDeque* marking_deque, 2040 PagedSpace* space) { 2041 if (!space->was_swept_conservatively()) { 2042 HeapObjectIterator it(space); 2043 DiscoverGreyObjectsWithIterator(heap, marking_deque, &it); 2044 } else { 2045 PageIterator it(space); 2046 while (it.has_next()) { 2047 Page* p = it.next(); 2048 DiscoverGreyObjectsOnPage(marking_deque, p); 2049 if (marking_deque->IsFull()) return; 2050 } 2051 } 2052 } 2053 2054 2055 static void DiscoverGreyObjectsInNewSpace(Heap* heap, 2056 MarkingDeque* marking_deque) { 2057 NewSpace* space = heap->new_space(); 2058 NewSpacePageIterator it(space->bottom(), space->top()); 2059 while (it.has_next()) { 2060 NewSpacePage* page = it.next(); 2061 DiscoverGreyObjectsOnPage(marking_deque, page); 2062 if (marking_deque->IsFull()) return; 2063 } 2064 } 2065 2066 2067 bool MarkCompactCollector::IsUnmarkedHeapObject(Object** p) { 2068 Object* o = *p; 2069 if (!o->IsHeapObject()) return false; 2070 HeapObject* heap_object = HeapObject::cast(o); 2071 MarkBit mark = Marking::MarkBitFrom(heap_object); 2072 return !mark.Get(); 2073 } 2074 2075 2076 bool MarkCompactCollector::IsUnmarkedHeapObjectWithHeap(Heap* heap, 2077 Object** p) { 2078 Object* o = *p; 2079 ASSERT(o->IsHeapObject()); 2080 HeapObject* heap_object = HeapObject::cast(o); 2081 MarkBit mark = Marking::MarkBitFrom(heap_object); 2082 return !mark.Get(); 2083 } 2084 2085 2086 void MarkCompactCollector::MarkStringTable(RootMarkingVisitor* visitor) { 2087 StringTable* string_table = heap()->string_table(); 2088 // Mark the string table itself. 2089 MarkBit string_table_mark = Marking::MarkBitFrom(string_table); 2090 SetMark(string_table, string_table_mark); 2091 // Explicitly mark the prefix. 2092 string_table->IteratePrefix(visitor); 2093 ProcessMarkingDeque(); 2094 } 2095 2096 2097 void MarkCompactCollector::MarkAllocationSite(AllocationSite* site) { 2098 MarkBit mark_bit = Marking::MarkBitFrom(site); 2099 SetMark(site, mark_bit); 2100 } 2101 2102 2103 void MarkCompactCollector::MarkRoots(RootMarkingVisitor* visitor) { 2104 // Mark the heap roots including global variables, stack variables, 2105 // etc., and all objects reachable from them. 2106 heap()->IterateStrongRoots(visitor, VISIT_ONLY_STRONG); 2107 2108 // Handle the string table specially. 2109 MarkStringTable(visitor); 2110 2111 MarkWeakObjectToCodeTable(); 2112 2113 // There may be overflowed objects in the heap. Visit them now. 2114 while (marking_deque_.overflowed()) { 2115 RefillMarkingDeque(); 2116 EmptyMarkingDeque(); 2117 } 2118 } 2119 2120 2121 void MarkCompactCollector::MarkImplicitRefGroups() { 2122 List<ImplicitRefGroup*>* ref_groups = 2123 isolate()->global_handles()->implicit_ref_groups(); 2124 2125 int last = 0; 2126 for (int i = 0; i < ref_groups->length(); i++) { 2127 ImplicitRefGroup* entry = ref_groups->at(i); 2128 ASSERT(entry != NULL); 2129 2130 if (!IsMarked(*entry->parent)) { 2131 (*ref_groups)[last++] = entry; 2132 continue; 2133 } 2134 2135 Object*** children = entry->children; 2136 // A parent object is marked, so mark all child heap objects. 2137 for (size_t j = 0; j < entry->length; ++j) { 2138 if ((*children[j])->IsHeapObject()) { 2139 HeapObject* child = HeapObject::cast(*children[j]); 2140 MarkBit mark = Marking::MarkBitFrom(child); 2141 MarkObject(child, mark); 2142 } 2143 } 2144 2145 // Once the entire group has been marked, dispose it because it's 2146 // not needed anymore. 2147 delete entry; 2148 } 2149 ref_groups->Rewind(last); 2150 } 2151 2152 2153 void MarkCompactCollector::MarkWeakObjectToCodeTable() { 2154 HeapObject* weak_object_to_code_table = 2155 HeapObject::cast(heap()->weak_object_to_code_table()); 2156 if (!IsMarked(weak_object_to_code_table)) { 2157 MarkBit mark = Marking::MarkBitFrom(weak_object_to_code_table); 2158 SetMark(weak_object_to_code_table, mark); 2159 } 2160 } 2161 2162 2163 // Mark all objects reachable from the objects on the marking stack. 2164 // Before: the marking stack contains zero or more heap object pointers. 2165 // After: the marking stack is empty, and all objects reachable from the 2166 // marking stack have been marked, or are overflowed in the heap. 2167 void MarkCompactCollector::EmptyMarkingDeque() { 2168 while (!marking_deque_.IsEmpty()) { 2169 HeapObject* object = marking_deque_.Pop(); 2170 ASSERT(object->IsHeapObject()); 2171 ASSERT(heap()->Contains(object)); 2172 ASSERT(Marking::IsBlack(Marking::MarkBitFrom(object))); 2173 2174 Map* map = object->map(); 2175 MarkBit map_mark = Marking::MarkBitFrom(map); 2176 MarkObject(map, map_mark); 2177 2178 MarkCompactMarkingVisitor::IterateBody(map, object); 2179 } 2180 } 2181 2182 2183 // Sweep the heap for overflowed objects, clear their overflow bits, and 2184 // push them on the marking stack. Stop early if the marking stack fills 2185 // before sweeping completes. If sweeping completes, there are no remaining 2186 // overflowed objects in the heap so the overflow flag on the markings stack 2187 // is cleared. 2188 void MarkCompactCollector::RefillMarkingDeque() { 2189 ASSERT(marking_deque_.overflowed()); 2190 2191 DiscoverGreyObjectsInNewSpace(heap(), &marking_deque_); 2192 if (marking_deque_.IsFull()) return; 2193 2194 DiscoverGreyObjectsInSpace(heap(), 2195 &marking_deque_, 2196 heap()->old_pointer_space()); 2197 if (marking_deque_.IsFull()) return; 2198 2199 DiscoverGreyObjectsInSpace(heap(), 2200 &marking_deque_, 2201 heap()->old_data_space()); 2202 if (marking_deque_.IsFull()) return; 2203 2204 DiscoverGreyObjectsInSpace(heap(), 2205 &marking_deque_, 2206 heap()->code_space()); 2207 if (marking_deque_.IsFull()) return; 2208 2209 DiscoverGreyObjectsInSpace(heap(), 2210 &marking_deque_, 2211 heap()->map_space()); 2212 if (marking_deque_.IsFull()) return; 2213 2214 DiscoverGreyObjectsInSpace(heap(), 2215 &marking_deque_, 2216 heap()->cell_space()); 2217 if (marking_deque_.IsFull()) return; 2218 2219 DiscoverGreyObjectsInSpace(heap(), 2220 &marking_deque_, 2221 heap()->property_cell_space()); 2222 if (marking_deque_.IsFull()) return; 2223 2224 LargeObjectIterator lo_it(heap()->lo_space()); 2225 DiscoverGreyObjectsWithIterator(heap(), 2226 &marking_deque_, 2227 &lo_it); 2228 if (marking_deque_.IsFull()) return; 2229 2230 marking_deque_.ClearOverflowed(); 2231 } 2232 2233 2234 // Mark all objects reachable (transitively) from objects on the marking 2235 // stack. Before: the marking stack contains zero or more heap object 2236 // pointers. After: the marking stack is empty and there are no overflowed 2237 // objects in the heap. 2238 void MarkCompactCollector::ProcessMarkingDeque() { 2239 EmptyMarkingDeque(); 2240 while (marking_deque_.overflowed()) { 2241 RefillMarkingDeque(); 2242 EmptyMarkingDeque(); 2243 } 2244 } 2245 2246 2247 // Mark all objects reachable (transitively) from objects on the marking 2248 // stack including references only considered in the atomic marking pause. 2249 void MarkCompactCollector::ProcessEphemeralMarking(ObjectVisitor* visitor) { 2250 bool work_to_do = true; 2251 ASSERT(marking_deque_.IsEmpty()); 2252 while (work_to_do) { 2253 isolate()->global_handles()->IterateObjectGroups( 2254 visitor, &IsUnmarkedHeapObjectWithHeap); 2255 MarkImplicitRefGroups(); 2256 ProcessWeakCollections(); 2257 work_to_do = !marking_deque_.IsEmpty(); 2258 ProcessMarkingDeque(); 2259 } 2260 } 2261 2262 2263 void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor) { 2264 for (StackFrameIterator it(isolate(), isolate()->thread_local_top()); 2265 !it.done(); it.Advance()) { 2266 if (it.frame()->type() == StackFrame::JAVA_SCRIPT) { 2267 return; 2268 } 2269 if (it.frame()->type() == StackFrame::OPTIMIZED) { 2270 Code* code = it.frame()->LookupCode(); 2271 if (!code->CanDeoptAt(it.frame()->pc())) { 2272 code->CodeIterateBody(visitor); 2273 } 2274 ProcessMarkingDeque(); 2275 return; 2276 } 2277 } 2278 } 2279 2280 2281 void MarkCompactCollector::MarkLiveObjects() { 2282 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_MARK); 2283 // The recursive GC marker detects when it is nearing stack overflow, 2284 // and switches to a different marking system. JS interrupts interfere 2285 // with the C stack limit check. 2286 PostponeInterruptsScope postpone(isolate()); 2287 2288 bool incremental_marking_overflowed = false; 2289 IncrementalMarking* incremental_marking = heap_->incremental_marking(); 2290 if (was_marked_incrementally_) { 2291 // Finalize the incremental marking and check whether we had an overflow. 2292 // Both markers use grey color to mark overflowed objects so 2293 // non-incremental marker can deal with them as if overflow 2294 // occured during normal marking. 2295 // But incremental marker uses a separate marking deque 2296 // so we have to explicitly copy its overflow state. 2297 incremental_marking->Finalize(); 2298 incremental_marking_overflowed = 2299 incremental_marking->marking_deque()->overflowed(); 2300 incremental_marking->marking_deque()->ClearOverflowed(); 2301 } else { 2302 // Abort any pending incremental activities e.g. incremental sweeping. 2303 incremental_marking->Abort(); 2304 } 2305 2306 #ifdef DEBUG 2307 ASSERT(state_ == PREPARE_GC); 2308 state_ = MARK_LIVE_OBJECTS; 2309 #endif 2310 // The to space contains live objects, a page in from space is used as a 2311 // marking stack. 2312 Address marking_deque_start = heap()->new_space()->FromSpacePageLow(); 2313 Address marking_deque_end = heap()->new_space()->FromSpacePageHigh(); 2314 if (FLAG_force_marking_deque_overflows) { 2315 marking_deque_end = marking_deque_start + 64 * kPointerSize; 2316 } 2317 marking_deque_.Initialize(marking_deque_start, 2318 marking_deque_end); 2319 ASSERT(!marking_deque_.overflowed()); 2320 2321 if (incremental_marking_overflowed) { 2322 // There are overflowed objects left in the heap after incremental marking. 2323 marking_deque_.SetOverflowed(); 2324 } 2325 2326 PrepareForCodeFlushing(); 2327 2328 if (was_marked_incrementally_) { 2329 // There is no write barrier on cells so we have to scan them now at the end 2330 // of the incremental marking. 2331 { 2332 HeapObjectIterator cell_iterator(heap()->cell_space()); 2333 HeapObject* cell; 2334 while ((cell = cell_iterator.Next()) != NULL) { 2335 ASSERT(cell->IsCell()); 2336 if (IsMarked(cell)) { 2337 int offset = Cell::kValueOffset; 2338 MarkCompactMarkingVisitor::VisitPointer( 2339 heap(), 2340 reinterpret_cast<Object**>(cell->address() + offset)); 2341 } 2342 } 2343 } 2344 { 2345 HeapObjectIterator js_global_property_cell_iterator( 2346 heap()->property_cell_space()); 2347 HeapObject* cell; 2348 while ((cell = js_global_property_cell_iterator.Next()) != NULL) { 2349 ASSERT(cell->IsPropertyCell()); 2350 if (IsMarked(cell)) { 2351 MarkCompactMarkingVisitor::VisitPropertyCell(cell->map(), cell); 2352 } 2353 } 2354 } 2355 } 2356 2357 RootMarkingVisitor root_visitor(heap()); 2358 MarkRoots(&root_visitor); 2359 2360 ProcessTopOptimizedFrame(&root_visitor); 2361 2362 // The objects reachable from the roots are marked, yet unreachable 2363 // objects are unmarked. Mark objects reachable due to host 2364 // application specific logic or through Harmony weak maps. 2365 ProcessEphemeralMarking(&root_visitor); 2366 2367 // The objects reachable from the roots, weak maps or object groups 2368 // are marked, yet unreachable objects are unmarked. Mark objects 2369 // reachable only from weak global handles. 2370 // 2371 // First we identify nonlive weak handles and mark them as pending 2372 // destruction. 2373 heap()->isolate()->global_handles()->IdentifyWeakHandles( 2374 &IsUnmarkedHeapObject); 2375 // Then we mark the objects and process the transitive closure. 2376 heap()->isolate()->global_handles()->IterateWeakRoots(&root_visitor); 2377 while (marking_deque_.overflowed()) { 2378 RefillMarkingDeque(); 2379 EmptyMarkingDeque(); 2380 } 2381 2382 // Repeat host application specific and Harmony weak maps marking to 2383 // mark unmarked objects reachable from the weak roots. 2384 ProcessEphemeralMarking(&root_visitor); 2385 2386 AfterMarking(); 2387 } 2388 2389 2390 void MarkCompactCollector::AfterMarking() { 2391 // Object literal map caches reference strings (cache keys) and maps 2392 // (cache values). At this point still useful maps have already been 2393 // marked. Mark the keys for the alive values before we process the 2394 // string table. 2395 ProcessMapCaches(); 2396 2397 // Prune the string table removing all strings only pointed to by the 2398 // string table. Cannot use string_table() here because the string 2399 // table is marked. 2400 StringTable* string_table = heap()->string_table(); 2401 StringTableCleaner v(heap()); 2402 string_table->IterateElements(&v); 2403 string_table->ElementsRemoved(v.PointersRemoved()); 2404 heap()->external_string_table_.Iterate(&v); 2405 heap()->external_string_table_.CleanUp(); 2406 2407 // Process the weak references. 2408 MarkCompactWeakObjectRetainer mark_compact_object_retainer; 2409 heap()->ProcessWeakReferences(&mark_compact_object_retainer); 2410 2411 // Remove object groups after marking phase. 2412 heap()->isolate()->global_handles()->RemoveObjectGroups(); 2413 heap()->isolate()->global_handles()->RemoveImplicitRefGroups(); 2414 2415 // Flush code from collected candidates. 2416 if (is_code_flushing_enabled()) { 2417 code_flusher_->ProcessCandidates(); 2418 // If incremental marker does not support code flushing, we need to 2419 // disable it before incremental marking steps for next cycle. 2420 if (FLAG_flush_code && !FLAG_flush_code_incrementally) { 2421 EnableCodeFlushing(false); 2422 } 2423 } 2424 2425 if (!FLAG_watch_ic_patching) { 2426 // Clean up dead objects from the runtime profiler. 2427 heap()->isolate()->runtime_profiler()->RemoveDeadSamples(); 2428 } 2429 2430 if (FLAG_track_gc_object_stats) { 2431 heap()->CheckpointObjectStats(); 2432 } 2433 } 2434 2435 2436 void MarkCompactCollector::ProcessMapCaches() { 2437 Object* raw_context = heap()->native_contexts_list_; 2438 while (raw_context != heap()->undefined_value()) { 2439 Context* context = reinterpret_cast<Context*>(raw_context); 2440 if (IsMarked(context)) { 2441 HeapObject* raw_map_cache = 2442 HeapObject::cast(context->get(Context::MAP_CACHE_INDEX)); 2443 // A map cache may be reachable from the stack. In this case 2444 // it's already transitively marked and it's too late to clean 2445 // up its parts. 2446 if (!IsMarked(raw_map_cache) && 2447 raw_map_cache != heap()->undefined_value()) { 2448 MapCache* map_cache = reinterpret_cast<MapCache*>(raw_map_cache); 2449 int existing_elements = map_cache->NumberOfElements(); 2450 int used_elements = 0; 2451 for (int i = MapCache::kElementsStartIndex; 2452 i < map_cache->length(); 2453 i += MapCache::kEntrySize) { 2454 Object* raw_key = map_cache->get(i); 2455 if (raw_key == heap()->undefined_value() || 2456 raw_key == heap()->the_hole_value()) continue; 2457 STATIC_ASSERT(MapCache::kEntrySize == 2); 2458 Object* raw_map = map_cache->get(i + 1); 2459 if (raw_map->IsHeapObject() && IsMarked(raw_map)) { 2460 ++used_elements; 2461 } else { 2462 // Delete useless entries with unmarked maps. 2463 ASSERT(raw_map->IsMap()); 2464 map_cache->set_the_hole(i); 2465 map_cache->set_the_hole(i + 1); 2466 } 2467 } 2468 if (used_elements == 0) { 2469 context->set(Context::MAP_CACHE_INDEX, heap()->undefined_value()); 2470 } else { 2471 // Note: we don't actually shrink the cache here to avoid 2472 // extra complexity during GC. We rely on subsequent cache 2473 // usages (EnsureCapacity) to do this. 2474 map_cache->ElementsRemoved(existing_elements - used_elements); 2475 MarkBit map_cache_markbit = Marking::MarkBitFrom(map_cache); 2476 MarkObject(map_cache, map_cache_markbit); 2477 } 2478 } 2479 } 2480 // Move to next element in the list. 2481 raw_context = context->get(Context::NEXT_CONTEXT_LINK); 2482 } 2483 ProcessMarkingDeque(); 2484 } 2485 2486 2487 void MarkCompactCollector::ReattachInitialMaps() { 2488 HeapObjectIterator map_iterator(heap()->map_space()); 2489 for (HeapObject* obj = map_iterator.Next(); 2490 obj != NULL; 2491 obj = map_iterator.Next()) { 2492 Map* map = Map::cast(obj); 2493 2494 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); 2495 if (map->instance_type() < FIRST_JS_RECEIVER_TYPE) continue; 2496 2497 if (map->attached_to_shared_function_info()) { 2498 JSFunction::cast(map->constructor())->shared()->AttachInitialMap(map); 2499 } 2500 } 2501 } 2502 2503 2504 void MarkCompactCollector::ClearNonLiveReferences() { 2505 // Iterate over the map space, setting map transitions that go from 2506 // a marked map to an unmarked map to null transitions. This action 2507 // is carried out only on maps of JSObjects and related subtypes. 2508 HeapObjectIterator map_iterator(heap()->map_space()); 2509 for (HeapObject* obj = map_iterator.Next(); 2510 obj != NULL; 2511 obj = map_iterator.Next()) { 2512 Map* map = Map::cast(obj); 2513 2514 if (!map->CanTransition()) continue; 2515 2516 MarkBit map_mark = Marking::MarkBitFrom(map); 2517 if (map_mark.Get() && map->attached_to_shared_function_info()) { 2518 // This map is used for inobject slack tracking and has been detached 2519 // from SharedFunctionInfo during the mark phase. 2520 // Since it survived the GC, reattach it now. 2521 JSFunction::cast(map->constructor())->shared()->AttachInitialMap(map); 2522 } 2523 2524 ClearNonLivePrototypeTransitions(map); 2525 ClearNonLiveMapTransitions(map, map_mark); 2526 2527 if (map_mark.Get()) { 2528 ClearNonLiveDependentCode(map->dependent_code()); 2529 } else { 2530 ClearAndDeoptimizeDependentCode(map->dependent_code()); 2531 map->set_dependent_code(DependentCode::cast(heap()->empty_fixed_array())); 2532 } 2533 } 2534 2535 // Iterate over property cell space, removing dependent code that is not 2536 // otherwise kept alive by strong references. 2537 HeapObjectIterator cell_iterator(heap_->property_cell_space()); 2538 for (HeapObject* cell = cell_iterator.Next(); 2539 cell != NULL; 2540 cell = cell_iterator.Next()) { 2541 if (IsMarked(cell)) { 2542 ClearNonLiveDependentCode(PropertyCell::cast(cell)->dependent_code()); 2543 } 2544 } 2545 2546 // Iterate over allocation sites, removing dependent code that is not 2547 // otherwise kept alive by strong references. 2548 Object* undefined = heap()->undefined_value(); 2549 for (Object* site = heap()->allocation_sites_list(); 2550 site != undefined; 2551 site = AllocationSite::cast(site)->weak_next()) { 2552 if (IsMarked(site)) { 2553 ClearNonLiveDependentCode(AllocationSite::cast(site)->dependent_code()); 2554 } 2555 } 2556 2557 if (heap_->weak_object_to_code_table()->IsHashTable()) { 2558 WeakHashTable* table = 2559 WeakHashTable::cast(heap_->weak_object_to_code_table()); 2560 uint32_t capacity = table->Capacity(); 2561 for (uint32_t i = 0; i < capacity; i++) { 2562 uint32_t key_index = table->EntryToIndex(i); 2563 Object* key = table->get(key_index); 2564 if (!table->IsKey(key)) continue; 2565 uint32_t value_index = table->EntryToValueIndex(i); 2566 Object* value = table->get(value_index); 2567 if (IsMarked(key)) { 2568 if (!IsMarked(value)) { 2569 HeapObject* obj = HeapObject::cast(value); 2570 MarkBit mark = Marking::MarkBitFrom(obj); 2571 SetMark(obj, mark); 2572 } 2573 ClearNonLiveDependentCode(DependentCode::cast(value)); 2574 } else { 2575 ClearAndDeoptimizeDependentCode(DependentCode::cast(value)); 2576 table->set(key_index, heap_->the_hole_value()); 2577 table->set(value_index, heap_->the_hole_value()); 2578 } 2579 } 2580 } 2581 } 2582 2583 2584 void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) { 2585 int number_of_transitions = map->NumberOfProtoTransitions(); 2586 FixedArray* prototype_transitions = map->GetPrototypeTransitions(); 2587 2588 int new_number_of_transitions = 0; 2589 const int header = Map::kProtoTransitionHeaderSize; 2590 const int proto_offset = header + Map::kProtoTransitionPrototypeOffset; 2591 const int map_offset = header + Map::kProtoTransitionMapOffset; 2592 const int step = Map::kProtoTransitionElementsPerEntry; 2593 for (int i = 0; i < number_of_transitions; i++) { 2594 Object* prototype = prototype_transitions->get(proto_offset + i * step); 2595 Object* cached_map = prototype_transitions->get(map_offset + i * step); 2596 if (IsMarked(prototype) && IsMarked(cached_map)) { 2597 ASSERT(!prototype->IsUndefined()); 2598 int proto_index = proto_offset + new_number_of_transitions * step; 2599 int map_index = map_offset + new_number_of_transitions * step; 2600 if (new_number_of_transitions != i) { 2601 prototype_transitions->set( 2602 proto_index, 2603 prototype, 2604 UPDATE_WRITE_BARRIER); 2605 prototype_transitions->set( 2606 map_index, 2607 cached_map, 2608 SKIP_WRITE_BARRIER); 2609 } 2610 Object** slot = 2611 HeapObject::RawField(prototype_transitions, 2612 FixedArray::OffsetOfElementAt(proto_index)); 2613 RecordSlot(slot, slot, prototype); 2614 new_number_of_transitions++; 2615 } 2616 } 2617 2618 if (new_number_of_transitions != number_of_transitions) { 2619 map->SetNumberOfProtoTransitions(new_number_of_transitions); 2620 } 2621 2622 // Fill slots that became free with undefined value. 2623 for (int i = new_number_of_transitions * step; 2624 i < number_of_transitions * step; 2625 i++) { 2626 prototype_transitions->set_undefined(header + i); 2627 } 2628 } 2629 2630 2631 void MarkCompactCollector::ClearNonLiveMapTransitions(Map* map, 2632 MarkBit map_mark) { 2633 Object* potential_parent = map->GetBackPointer(); 2634 if (!potential_parent->IsMap()) return; 2635 Map* parent = Map::cast(potential_parent); 2636 2637 // Follow back pointer, check whether we are dealing with a map transition 2638 // from a live map to a dead path and in case clear transitions of parent. 2639 bool current_is_alive = map_mark.Get(); 2640 bool parent_is_alive = Marking::MarkBitFrom(parent).Get(); 2641 if (!current_is_alive && parent_is_alive) { 2642 parent->ClearNonLiveTransitions(heap()); 2643 } 2644 } 2645 2646 2647 void MarkCompactCollector::ClearAndDeoptimizeDependentCode( 2648 DependentCode* entries) { 2649 DisallowHeapAllocation no_allocation; 2650 DependentCode::GroupStartIndexes starts(entries); 2651 int number_of_entries = starts.number_of_entries(); 2652 if (number_of_entries == 0) return; 2653 for (int i = 0; i < number_of_entries; i++) { 2654 // If the entry is compilation info then the map must be alive, 2655 // and ClearAndDeoptimizeDependentCode shouldn't be called. 2656 ASSERT(entries->is_code_at(i)); 2657 Code* code = entries->code_at(i); 2658 2659 if (IsMarked(code) && !code->marked_for_deoptimization()) { 2660 code->set_marked_for_deoptimization(true); 2661 code->InvalidateEmbeddedObjects(); 2662 have_code_to_deoptimize_ = true; 2663 } 2664 entries->clear_at(i); 2665 } 2666 } 2667 2668 2669 void MarkCompactCollector::ClearNonLiveDependentCode(DependentCode* entries) { 2670 DisallowHeapAllocation no_allocation; 2671 DependentCode::GroupStartIndexes starts(entries); 2672 int number_of_entries = starts.number_of_entries(); 2673 if (number_of_entries == 0) return; 2674 int new_number_of_entries = 0; 2675 // Go through all groups, remove dead codes and compact. 2676 for (int g = 0; g < DependentCode::kGroupCount; g++) { 2677 int group_number_of_entries = 0; 2678 for (int i = starts.at(g); i < starts.at(g + 1); i++) { 2679 Object* obj = entries->object_at(i); 2680 ASSERT(obj->IsCode() || IsMarked(obj)); 2681 if (IsMarked(obj) && 2682 (!obj->IsCode() || !WillBeDeoptimized(Code::cast(obj)))) { 2683 if (new_number_of_entries + group_number_of_entries != i) { 2684 entries->set_object_at( 2685 new_number_of_entries + group_number_of_entries, obj); 2686 } 2687 Object** slot = entries->slot_at(new_number_of_entries + 2688 group_number_of_entries); 2689 RecordSlot(slot, slot, obj); 2690 group_number_of_entries++; 2691 } 2692 } 2693 entries->set_number_of_entries( 2694 static_cast<DependentCode::DependencyGroup>(g), 2695 group_number_of_entries); 2696 new_number_of_entries += group_number_of_entries; 2697 } 2698 for (int i = new_number_of_entries; i < number_of_entries; i++) { 2699 entries->clear_at(i); 2700 } 2701 } 2702 2703 2704 void MarkCompactCollector::ProcessWeakCollections() { 2705 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_WEAKCOLLECTION_PROCESS); 2706 Object* weak_collection_obj = encountered_weak_collections(); 2707 while (weak_collection_obj != Smi::FromInt(0)) { 2708 ASSERT(MarkCompactCollector::IsMarked( 2709 HeapObject::cast(weak_collection_obj))); 2710 JSWeakCollection* weak_collection = 2711 reinterpret_cast<JSWeakCollection*>(weak_collection_obj); 2712 ObjectHashTable* table = ObjectHashTable::cast(weak_collection->table()); 2713 Object** anchor = reinterpret_cast<Object**>(table->address()); 2714 for (int i = 0; i < table->Capacity(); i++) { 2715 if (MarkCompactCollector::IsMarked(HeapObject::cast(table->KeyAt(i)))) { 2716 Object** key_slot = 2717 HeapObject::RawField(table, FixedArray::OffsetOfElementAt( 2718 ObjectHashTable::EntryToIndex(i))); 2719 RecordSlot(anchor, key_slot, *key_slot); 2720 Object** value_slot = 2721 HeapObject::RawField(table, FixedArray::OffsetOfElementAt( 2722 ObjectHashTable::EntryToValueIndex(i))); 2723 MarkCompactMarkingVisitor::MarkObjectByPointer( 2724 this, anchor, value_slot); 2725 } 2726 } 2727 weak_collection_obj = weak_collection->next(); 2728 } 2729 } 2730 2731 2732 void MarkCompactCollector::ClearWeakCollections() { 2733 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_WEAKCOLLECTION_CLEAR); 2734 Object* weak_collection_obj = encountered_weak_collections(); 2735 while (weak_collection_obj != Smi::FromInt(0)) { 2736 ASSERT(MarkCompactCollector::IsMarked( 2737 HeapObject::cast(weak_collection_obj))); 2738 JSWeakCollection* weak_collection = 2739 reinterpret_cast<JSWeakCollection*>(weak_collection_obj); 2740 ObjectHashTable* table = ObjectHashTable::cast(weak_collection->table()); 2741 for (int i = 0; i < table->Capacity(); i++) { 2742 if (!MarkCompactCollector::IsMarked(HeapObject::cast(table->KeyAt(i)))) { 2743 table->RemoveEntry(i); 2744 } 2745 } 2746 weak_collection_obj = weak_collection->next(); 2747 weak_collection->set_next(Smi::FromInt(0)); 2748 } 2749 set_encountered_weak_collections(Smi::FromInt(0)); 2750 } 2751 2752 2753 // We scavange new space simultaneously with sweeping. This is done in two 2754 // passes. 2755 // 2756 // The first pass migrates all alive objects from one semispace to another or 2757 // promotes them to old space. Forwarding address is written directly into 2758 // first word of object without any encoding. If object is dead we write 2759 // NULL as a forwarding address. 2760 // 2761 // The second pass updates pointers to new space in all spaces. It is possible 2762 // to encounter pointers to dead new space objects during traversal of pointers 2763 // to new space. We should clear them to avoid encountering them during next 2764 // pointer iteration. This is an issue if the store buffer overflows and we 2765 // have to scan the entire old space, including dead objects, looking for 2766 // pointers to new space. 2767 void MarkCompactCollector::MigrateObject(Address dst, 2768 Address src, 2769 int size, 2770 AllocationSpace dest) { 2771 HeapProfiler* heap_profiler = heap()->isolate()->heap_profiler(); 2772 if (heap_profiler->is_tracking_object_moves()) { 2773 heap_profiler->ObjectMoveEvent(src, dst, size); 2774 } 2775 ASSERT(heap()->AllowedToBeMigrated(HeapObject::FromAddress(src), dest)); 2776 ASSERT(dest != LO_SPACE && size <= Page::kMaxNonCodeHeapObjectSize); 2777 if (dest == OLD_POINTER_SPACE) { 2778 Address src_slot = src; 2779 Address dst_slot = dst; 2780 ASSERT(IsAligned(size, kPointerSize)); 2781 2782 for (int remaining = size / kPointerSize; remaining > 0; remaining--) { 2783 Object* value = Memory::Object_at(src_slot); 2784 2785 Memory::Object_at(dst_slot) = value; 2786 2787 if (heap_->InNewSpace(value)) { 2788 heap_->store_buffer()->Mark(dst_slot); 2789 } else if (value->IsHeapObject() && IsOnEvacuationCandidate(value)) { 2790 SlotsBuffer::AddTo(&slots_buffer_allocator_, 2791 &migration_slots_buffer_, 2792 reinterpret_cast<Object**>(dst_slot), 2793 SlotsBuffer::IGNORE_OVERFLOW); 2794 } 2795 2796 src_slot += kPointerSize; 2797 dst_slot += kPointerSize; 2798 } 2799 2800 if (compacting_ && HeapObject::FromAddress(dst)->IsJSFunction()) { 2801 Address code_entry_slot = dst + JSFunction::kCodeEntryOffset; 2802 Address code_entry = Memory::Address_at(code_entry_slot); 2803 2804 if (Page::FromAddress(code_entry)->IsEvacuationCandidate()) { 2805 SlotsBuffer::AddTo(&slots_buffer_allocator_, 2806 &migration_slots_buffer_, 2807 SlotsBuffer::CODE_ENTRY_SLOT, 2808 code_entry_slot, 2809 SlotsBuffer::IGNORE_OVERFLOW); 2810 } 2811 } 2812 } else if (dest == CODE_SPACE) { 2813 PROFILE(isolate(), CodeMoveEvent(src, dst)); 2814 heap()->MoveBlock(dst, src, size); 2815 SlotsBuffer::AddTo(&slots_buffer_allocator_, 2816 &migration_slots_buffer_, 2817 SlotsBuffer::RELOCATED_CODE_OBJECT, 2818 dst, 2819 SlotsBuffer::IGNORE_OVERFLOW); 2820 Code::cast(HeapObject::FromAddress(dst))->Relocate(dst - src); 2821 } else { 2822 ASSERT(dest == OLD_DATA_SPACE || dest == NEW_SPACE); 2823 heap()->MoveBlock(dst, src, size); 2824 } 2825 Memory::Address_at(src) = dst; 2826 } 2827 2828 2829 // Visitor for updating pointers from live objects in old spaces to new space. 2830 // It does not expect to encounter pointers to dead objects. 2831 class PointersUpdatingVisitor: public ObjectVisitor { 2832 public: 2833 explicit PointersUpdatingVisitor(Heap* heap) : heap_(heap) { } 2834 2835 void VisitPointer(Object** p) { 2836 UpdatePointer(p); 2837 } 2838 2839 void VisitPointers(Object** start, Object** end) { 2840 for (Object** p = start; p < end; p++) UpdatePointer(p); 2841 } 2842 2843 void VisitEmbeddedPointer(RelocInfo* rinfo) { 2844 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); 2845 Object* target = rinfo->target_object(); 2846 Object* old_target = target; 2847 VisitPointer(&target); 2848 // Avoid unnecessary changes that might unnecessary flush the instruction 2849 // cache. 2850 if (target != old_target) { 2851 rinfo->set_target_object(target); 2852 } 2853 } 2854 2855 void VisitCodeTarget(RelocInfo* rinfo) { 2856 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); 2857 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); 2858 Object* old_target = target; 2859 VisitPointer(&target); 2860 if (target != old_target) { 2861 rinfo->set_target_address(Code::cast(target)->instruction_start()); 2862 } 2863 } 2864 2865 void VisitCodeAgeSequence(RelocInfo* rinfo) { 2866 ASSERT(RelocInfo::IsCodeAgeSequence(rinfo->rmode())); 2867 Object* stub = rinfo->code_age_stub(); 2868 ASSERT(stub != NULL); 2869 VisitPointer(&stub); 2870 if (stub != rinfo->code_age_stub()) { 2871 rinfo->set_code_age_stub(Code::cast(stub)); 2872 } 2873 } 2874 2875 void VisitDebugTarget(RelocInfo* rinfo) { 2876 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && 2877 rinfo->IsPatchedReturnSequence()) || 2878 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && 2879 rinfo->IsPatchedDebugBreakSlotSequence())); 2880 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); 2881 VisitPointer(&target); 2882 rinfo->set_call_address(Code::cast(target)->instruction_start()); 2883 } 2884 2885 static inline void UpdateSlot(Heap* heap, Object** slot) { 2886 Object* obj = *slot; 2887 2888 if (!obj->IsHeapObject()) return; 2889 2890 HeapObject* heap_obj = HeapObject::cast(obj); 2891 2892 MapWord map_word = heap_obj->map_word(); 2893 if (map_word.IsForwardingAddress()) { 2894 ASSERT(heap->InFromSpace(heap_obj) || 2895 MarkCompactCollector::IsOnEvacuationCandidate(heap_obj)); 2896 HeapObject* target = map_word.ToForwardingAddress(); 2897 *slot = target; 2898 ASSERT(!heap->InFromSpace(target) && 2899 !MarkCompactCollector::IsOnEvacuationCandidate(target)); 2900 } 2901 } 2902 2903 private: 2904 inline void UpdatePointer(Object** p) { 2905 UpdateSlot(heap_, p); 2906 } 2907 2908 Heap* heap_; 2909 }; 2910 2911 2912 static void UpdatePointer(HeapObject** p, HeapObject* object) { 2913 ASSERT(*p == object); 2914 2915 Address old_addr = object->address(); 2916 2917 Address new_addr = Memory::Address_at(old_addr); 2918 2919 // The new space sweep will overwrite the map word of dead objects 2920 // with NULL. In this case we do not need to transfer this entry to 2921 // the store buffer which we are rebuilding. 2922 if (new_addr != NULL) { 2923 *p = HeapObject::FromAddress(new_addr); 2924 } else { 2925 // We have to zap this pointer, because the store buffer may overflow later, 2926 // and then we have to scan the entire heap and we don't want to find 2927 // spurious newspace pointers in the old space. 2928 // TODO(mstarzinger): This was changed to a sentinel value to track down 2929 // rare crashes, change it back to Smi::FromInt(0) later. 2930 *p = reinterpret_cast<HeapObject*>(Smi::FromInt(0x0f100d00 >> 1)); // flood 2931 } 2932 } 2933 2934 2935 static String* UpdateReferenceInExternalStringTableEntry(Heap* heap, 2936 Object** p) { 2937 MapWord map_word = HeapObject::cast(*p)->map_word(); 2938 2939 if (map_word.IsForwardingAddress()) { 2940 return String::cast(map_word.ToForwardingAddress()); 2941 } 2942 2943 return String::cast(*p); 2944 } 2945 2946 2947 bool MarkCompactCollector::TryPromoteObject(HeapObject* object, 2948 int object_size) { 2949 // TODO(hpayer): Replace that check with an assert. 2950 CHECK(object_size <= Page::kMaxNonCodeHeapObjectSize); 2951 2952 OldSpace* target_space = heap()->TargetSpace(object); 2953 2954 ASSERT(target_space == heap()->old_pointer_space() || 2955 target_space == heap()->old_data_space()); 2956 Object* result; 2957 MaybeObject* maybe_result = target_space->AllocateRaw(object_size); 2958 if (maybe_result->ToObject(&result)) { 2959 HeapObject* target = HeapObject::cast(result); 2960 MigrateObject(target->address(), 2961 object->address(), 2962 object_size, 2963 target_space->identity()); 2964 heap()->mark_compact_collector()->tracer()-> 2965 increment_promoted_objects_size(object_size); 2966 return true; 2967 } 2968 2969 return false; 2970 } 2971 2972 2973 void MarkCompactCollector::EvacuateNewSpace() { 2974 // There are soft limits in the allocation code, designed trigger a mark 2975 // sweep collection by failing allocations. But since we are already in 2976 // a mark-sweep allocation, there is no sense in trying to trigger one. 2977 AlwaysAllocateScope scope; 2978 heap()->CheckNewSpaceExpansionCriteria(); 2979 2980 NewSpace* new_space = heap()->new_space(); 2981 2982 // Store allocation range before flipping semispaces. 2983 Address from_bottom = new_space->bottom(); 2984 Address from_top = new_space->top(); 2985 2986 // Flip the semispaces. After flipping, to space is empty, from space has 2987 // live objects. 2988 new_space->Flip(); 2989 new_space->ResetAllocationInfo(); 2990 2991 int survivors_size = 0; 2992 2993 // First pass: traverse all objects in inactive semispace, remove marks, 2994 // migrate live objects and write forwarding addresses. This stage puts 2995 // new entries in the store buffer and may cause some pages to be marked 2996 // scan-on-scavenge. 2997 NewSpacePageIterator it(from_bottom, from_top); 2998 while (it.has_next()) { 2999 NewSpacePage* p = it.next(); 3000 survivors_size += DiscoverAndPromoteBlackObjectsOnPage(new_space, p); 3001 } 3002 3003 heap_->IncrementYoungSurvivorsCounter(survivors_size); 3004 new_space->set_age_mark(new_space->top()); 3005 } 3006 3007 3008 void MarkCompactCollector::EvacuateLiveObjectsFromPage(Page* p) { 3009 AlwaysAllocateScope always_allocate; 3010 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); 3011 ASSERT(p->IsEvacuationCandidate() && !p->WasSwept()); 3012 p->MarkSweptPrecisely(); 3013 3014 int offsets[16]; 3015 3016 for (MarkBitCellIterator it(p); !it.Done(); it.Advance()) { 3017 Address cell_base = it.CurrentCellBase(); 3018 MarkBit::CellType* cell = it.CurrentCell(); 3019 3020 if (*cell == 0) continue; 3021 3022 int live_objects = MarkWordToObjectStarts(*cell, offsets); 3023 for (int i = 0; i < live_objects; i++) { 3024 Address object_addr = cell_base + offsets[i] * kPointerSize; 3025 HeapObject* object = HeapObject::FromAddress(object_addr); 3026 ASSERT(Marking::IsBlack(Marking::MarkBitFrom(object))); 3027 3028 int size = object->Size(); 3029 3030 MaybeObject* target = space->AllocateRaw(size); 3031 if (target->IsFailure()) { 3032 // OS refused to give us memory. 3033 V8::FatalProcessOutOfMemory("Evacuation"); 3034 return; 3035 } 3036 3037 Object* target_object = target->ToObjectUnchecked(); 3038 3039 MigrateObject(HeapObject::cast(target_object)->address(), 3040 object_addr, 3041 size, 3042 space->identity()); 3043 ASSERT(object->map_word().IsForwardingAddress()); 3044 } 3045 3046 // Clear marking bits for current cell. 3047 *cell = 0; 3048 } 3049 p->ResetLiveBytes(); 3050 } 3051 3052 3053 void MarkCompactCollector::EvacuatePages() { 3054 int npages = evacuation_candidates_.length(); 3055 for (int i = 0; i < npages; i++) { 3056 Page* p = evacuation_candidates_[i]; 3057 ASSERT(p->IsEvacuationCandidate() || 3058 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); 3059 if (p->IsEvacuationCandidate()) { 3060 // During compaction we might have to request a new page. 3061 // Check that space still have room for that. 3062 if (static_cast<PagedSpace*>(p->owner())->CanExpand()) { 3063 EvacuateLiveObjectsFromPage(p); 3064 } else { 3065 // Without room for expansion evacuation is not guaranteed to succeed. 3066 // Pessimistically abandon unevacuated pages. 3067 for (int j = i; j < npages; j++) { 3068 Page* page = evacuation_candidates_[j]; 3069 slots_buffer_allocator_.DeallocateChain(page->slots_buffer_address()); 3070 page->ClearEvacuationCandidate(); 3071 page->SetFlag(Page::RESCAN_ON_EVACUATION); 3072 page->InsertAfter(static_cast<PagedSpace*>(page->owner())->anchor()); 3073 } 3074 return; 3075 } 3076 } 3077 } 3078 } 3079 3080 3081 class EvacuationWeakObjectRetainer : public WeakObjectRetainer { 3082 public: 3083 virtual Object* RetainAs(Object* object) { 3084 if (object->IsHeapObject()) { 3085 HeapObject* heap_object = HeapObject::cast(object); 3086 MapWord map_word = heap_object->map_word(); 3087 if (map_word.IsForwardingAddress()) { 3088 return map_word.ToForwardingAddress(); 3089 } 3090 } 3091 return object; 3092 } 3093 }; 3094 3095 3096 static inline void UpdateSlot(Isolate* isolate, 3097 ObjectVisitor* v, 3098 SlotsBuffer::SlotType slot_type, 3099 Address addr) { 3100 switch (slot_type) { 3101 case SlotsBuffer::CODE_TARGET_SLOT: { 3102 RelocInfo rinfo(addr, RelocInfo::CODE_TARGET, 0, NULL); 3103 rinfo.Visit(isolate, v); 3104 break; 3105 } 3106 case SlotsBuffer::CODE_ENTRY_SLOT: { 3107 v->VisitCodeEntry(addr); 3108 break; 3109 } 3110 case SlotsBuffer::RELOCATED_CODE_OBJECT: { 3111 HeapObject* obj = HeapObject::FromAddress(addr); 3112 Code::cast(obj)->CodeIterateBody(v); 3113 break; 3114 } 3115 case SlotsBuffer::DEBUG_TARGET_SLOT: { 3116 RelocInfo rinfo(addr, RelocInfo::DEBUG_BREAK_SLOT, 0, NULL); 3117 if (rinfo.IsPatchedDebugBreakSlotSequence()) rinfo.Visit(isolate, v); 3118 break; 3119 } 3120 case SlotsBuffer::JS_RETURN_SLOT: { 3121 RelocInfo rinfo(addr, RelocInfo::JS_RETURN, 0, NULL); 3122 if (rinfo.IsPatchedReturnSequence()) rinfo.Visit(isolate, v); 3123 break; 3124 } 3125 case SlotsBuffer::EMBEDDED_OBJECT_SLOT: { 3126 RelocInfo rinfo(addr, RelocInfo::EMBEDDED_OBJECT, 0, NULL); 3127 rinfo.Visit(isolate, v); 3128 break; 3129 } 3130 default: 3131 UNREACHABLE(); 3132 break; 3133 } 3134 } 3135 3136 3137 enum SweepingMode { 3138 SWEEP_ONLY, 3139 SWEEP_AND_VISIT_LIVE_OBJECTS 3140 }; 3141 3142 3143 enum SkipListRebuildingMode { 3144 REBUILD_SKIP_LIST, 3145 IGNORE_SKIP_LIST 3146 }; 3147 3148 3149 // Sweep a space precisely. After this has been done the space can 3150 // be iterated precisely, hitting only the live objects. Code space 3151 // is always swept precisely because we want to be able to iterate 3152 // over it. Map space is swept precisely, because it is not compacted. 3153 // Slots in live objects pointing into evacuation candidates are updated 3154 // if requested. 3155 template<SweepingMode sweeping_mode, SkipListRebuildingMode skip_list_mode> 3156 static void SweepPrecisely(PagedSpace* space, 3157 Page* p, 3158 ObjectVisitor* v) { 3159 ASSERT(!p->IsEvacuationCandidate() && !p->WasSwept()); 3160 ASSERT_EQ(skip_list_mode == REBUILD_SKIP_LIST, 3161 space->identity() == CODE_SPACE); 3162 ASSERT((p->skip_list() == NULL) || (skip_list_mode == REBUILD_SKIP_LIST)); 3163 3164 double start_time = 0.0; 3165 if (FLAG_print_cumulative_gc_stat) { 3166 start_time = OS::TimeCurrentMillis(); 3167 } 3168 3169 p->MarkSweptPrecisely(); 3170 3171 Address free_start = p->area_start(); 3172 ASSERT(reinterpret_cast<intptr_t>(free_start) % (32 * kPointerSize) == 0); 3173 int offsets[16]; 3174 3175 SkipList* skip_list = p->skip_list(); 3176 int curr_region = -1; 3177 if ((skip_list_mode == REBUILD_SKIP_LIST) && skip_list) { 3178 skip_list->Clear(); 3179 } 3180 3181 for (MarkBitCellIterator it(p); !it.Done(); it.Advance()) { 3182 Address cell_base = it.CurrentCellBase(); 3183 MarkBit::CellType* cell = it.CurrentCell(); 3184 int live_objects = MarkWordToObjectStarts(*cell, offsets); 3185 int live_index = 0; 3186 for ( ; live_objects != 0; live_objects--) { 3187 Address free_end = cell_base + offsets[live_index++] * kPointerSize; 3188 if (free_end != free_start) { 3189 space->Free(free_start, static_cast<int>(free_end - free_start)); 3190 #ifdef ENABLE_GDB_JIT_INTERFACE 3191 if (FLAG_gdbjit && space->identity() == CODE_SPACE) { 3192 GDBJITInterface::RemoveCodeRange(free_start, free_end); 3193 } 3194 #endif 3195 } 3196 HeapObject* live_object = HeapObject::FromAddress(free_end); 3197 ASSERT(Marking::IsBlack(Marking::MarkBitFrom(live_object))); 3198 Map* map = live_object->map(); 3199 int size = live_object->SizeFromMap(map); 3200 if (sweeping_mode == SWEEP_AND_VISIT_LIVE_OBJECTS) { 3201 live_object->IterateBody(map->instance_type(), size, v); 3202 } 3203 if ((skip_list_mode == REBUILD_SKIP_LIST) && skip_list != NULL) { 3204 int new_region_start = 3205 SkipList::RegionNumber(free_end); 3206 int new_region_end = 3207 SkipList::RegionNumber(free_end + size - kPointerSize); 3208 if (new_region_start != curr_region || 3209 new_region_end != curr_region) { 3210 skip_list->AddObject(free_end, size); 3211 curr_region = new_region_end; 3212 } 3213 } 3214 free_start = free_end + size; 3215 } 3216 // Clear marking bits for current cell. 3217 *cell = 0; 3218 } 3219 if (free_start != p->area_end()) { 3220 space->Free(free_start, static_cast<int>(p->area_end() - free_start)); 3221 #ifdef ENABLE_GDB_JIT_INTERFACE 3222 if (FLAG_gdbjit && space->identity() == CODE_SPACE) { 3223 GDBJITInterface::RemoveCodeRange(free_start, p->area_end()); 3224 } 3225 #endif 3226 } 3227 p->ResetLiveBytes(); 3228 if (FLAG_print_cumulative_gc_stat) { 3229 space->heap()->AddSweepingTime(OS::TimeCurrentMillis() - start_time); 3230 } 3231 } 3232 3233 3234 static bool SetMarkBitsUnderInvalidatedCode(Code* code, bool value) { 3235 Page* p = Page::FromAddress(code->address()); 3236 3237 if (p->IsEvacuationCandidate() || 3238 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) { 3239 return false; 3240 } 3241 3242 Address code_start = code->address(); 3243 Address code_end = code_start + code->Size(); 3244 3245 uint32_t start_index = MemoryChunk::FastAddressToMarkbitIndex(code_start); 3246 uint32_t end_index = 3247 MemoryChunk::FastAddressToMarkbitIndex(code_end - kPointerSize); 3248 3249 Bitmap* b = p->markbits(); 3250 3251 MarkBit start_mark_bit = b->MarkBitFromIndex(start_index); 3252 MarkBit end_mark_bit = b->MarkBitFromIndex(end_index); 3253 3254 MarkBit::CellType* start_cell = start_mark_bit.cell(); 3255 MarkBit::CellType* end_cell = end_mark_bit.cell(); 3256 3257 if (value) { 3258 MarkBit::CellType start_mask = ~(start_mark_bit.mask() - 1); 3259 MarkBit::CellType end_mask = (end_mark_bit.mask() << 1) - 1; 3260 3261 if (start_cell == end_cell) { 3262 *start_cell |= start_mask & end_mask; 3263 } else { 3264 *start_cell |= start_mask; 3265 for (MarkBit::CellType* cell = start_cell + 1; cell < end_cell; cell++) { 3266 *cell = ~0; 3267 } 3268 *end_cell |= end_mask; 3269 } 3270 } else { 3271 for (MarkBit::CellType* cell = start_cell ; cell <= end_cell; cell++) { 3272 *cell = 0; 3273 } 3274 } 3275 3276 return true; 3277 } 3278 3279 3280 static bool IsOnInvalidatedCodeObject(Address addr) { 3281 // We did not record any slots in large objects thus 3282 // we can safely go to the page from the slot address. 3283 Page* p = Page::FromAddress(addr); 3284 3285 // First check owner's identity because old pointer and old data spaces 3286 // are swept lazily and might still have non-zero mark-bits on some 3287 // pages. 3288 if (p->owner()->identity() != CODE_SPACE) return false; 3289 3290 // In code space only bits on evacuation candidates (but we don't record 3291 // any slots on them) and under invalidated code objects are non-zero. 3292 MarkBit mark_bit = 3293 p->markbits()->MarkBitFromIndex(Page::FastAddressToMarkbitIndex(addr)); 3294 3295 return mark_bit.Get(); 3296 } 3297 3298 3299 void MarkCompactCollector::InvalidateCode(Code* code) { 3300 if (heap_->incremental_marking()->IsCompacting() && 3301 !ShouldSkipEvacuationSlotRecording(code)) { 3302 ASSERT(compacting_); 3303 3304 // If the object is white than no slots were recorded on it yet. 3305 MarkBit mark_bit = Marking::MarkBitFrom(code); 3306 if (Marking::IsWhite(mark_bit)) return; 3307 3308 invalidated_code_.Add(code); 3309 } 3310 } 3311 3312 3313 // Return true if the given code is deoptimized or will be deoptimized. 3314 bool MarkCompactCollector::WillBeDeoptimized(Code* code) { 3315 return code->marked_for_deoptimization(); 3316 } 3317 3318 3319 bool MarkCompactCollector::MarkInvalidatedCode() { 3320 bool code_marked = false; 3321 3322 int length = invalidated_code_.length(); 3323 for (int i = 0; i < length; i++) { 3324 Code* code = invalidated_code_[i]; 3325 3326 if (SetMarkBitsUnderInvalidatedCode(code, true)) { 3327 code_marked = true; 3328 } 3329 } 3330 3331 return code_marked; 3332 } 3333 3334 3335 void MarkCompactCollector::RemoveDeadInvalidatedCode() { 3336 int length = invalidated_code_.length(); 3337 for (int i = 0; i < length; i++) { 3338 if (!IsMarked(invalidated_code_[i])) invalidated_code_[i] = NULL; 3339 } 3340 } 3341 3342 3343 void MarkCompactCollector::ProcessInvalidatedCode(ObjectVisitor* visitor) { 3344 int length = invalidated_code_.length(); 3345 for (int i = 0; i < length; i++) { 3346 Code* code = invalidated_code_[i]; 3347 if (code != NULL) { 3348 code->Iterate(visitor); 3349 SetMarkBitsUnderInvalidatedCode(code, false); 3350 } 3351 } 3352 invalidated_code_.Rewind(0); 3353 } 3354 3355 3356 void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { 3357 Heap::RelocationLock relocation_lock(heap()); 3358 3359 bool code_slots_filtering_required; 3360 { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP_NEWSPACE); 3361 code_slots_filtering_required = MarkInvalidatedCode(); 3362 EvacuateNewSpace(); 3363 } 3364 3365 { GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_EVACUATE_PAGES); 3366 EvacuatePages(); 3367 } 3368 3369 // Second pass: find pointers to new space and update them. 3370 PointersUpdatingVisitor updating_visitor(heap()); 3371 3372 { GCTracer::Scope gc_scope(tracer_, 3373 GCTracer::Scope::MC_UPDATE_NEW_TO_NEW_POINTERS); 3374 // Update pointers in to space. 3375 SemiSpaceIterator to_it(heap()->new_space()->bottom(), 3376 heap()->new_space()->top()); 3377 for (HeapObject* object = to_it.Next(); 3378 object != NULL; 3379 object = to_it.Next()) { 3380 Map* map = object->map(); 3381 object->IterateBody(map->instance_type(), 3382 object->SizeFromMap(map), 3383 &updating_visitor); 3384 } 3385 } 3386 3387 { GCTracer::Scope gc_scope(tracer_, 3388 GCTracer::Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS); 3389 // Update roots. 3390 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE); 3391 } 3392 3393 { GCTracer::Scope gc_scope(tracer_, 3394 GCTracer::Scope::MC_UPDATE_OLD_TO_NEW_POINTERS); 3395 StoreBufferRebuildScope scope(heap_, 3396 heap_->store_buffer(), 3397 &Heap::ScavengeStoreBufferCallback); 3398 heap_->store_buffer()->IteratePointersToNewSpaceAndClearMaps( 3399 &UpdatePointer); 3400 } 3401 3402 { GCTracer::Scope gc_scope(tracer_, 3403 GCTracer::Scope::MC_UPDATE_POINTERS_TO_EVACUATED); 3404 SlotsBuffer::UpdateSlotsRecordedIn(heap_, 3405 migration_slots_buffer_, 3406 code_slots_filtering_required); 3407 if (FLAG_trace_fragmentation) { 3408 PrintF(" migration slots buffer: %d\n", 3409 SlotsBuffer::SizeOfChain(migration_slots_buffer_)); 3410 } 3411 3412 if (compacting_ && was_marked_incrementally_) { 3413 // It's difficult to filter out slots recorded for large objects. 3414 LargeObjectIterator it(heap_->lo_space()); 3415 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) { 3416 // LargeObjectSpace is not swept yet thus we have to skip 3417 // dead objects explicitly. 3418 if (!IsMarked(obj)) continue; 3419 3420 Page* p = Page::FromAddress(obj->address()); 3421 if (p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) { 3422 obj->Iterate(&updating_visitor); 3423 p->ClearFlag(Page::RESCAN_ON_EVACUATION); 3424 } 3425 } 3426 } 3427 } 3428 3429 int npages = evacuation_candidates_.length(); 3430 { GCTracer::Scope gc_scope( 3431 tracer_, GCTracer::Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED); 3432 for (int i = 0; i < npages; i++) { 3433 Page* p = evacuation_candidates_[i]; 3434 ASSERT(p->IsEvacuationCandidate() || 3435 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); 3436 3437 if (p->IsEvacuationCandidate()) { 3438 SlotsBuffer::UpdateSlotsRecordedIn(heap_, 3439 p->slots_buffer(), 3440 code_slots_filtering_required); 3441 if (FLAG_trace_fragmentation) { 3442 PrintF(" page %p slots buffer: %d\n", 3443 reinterpret_cast<void*>(p), 3444 SlotsBuffer::SizeOfChain(p->slots_buffer())); 3445 } 3446 3447 // Important: skip list should be cleared only after roots were updated 3448 // because root iteration traverses the stack and might have to find 3449 // code objects from non-updated pc pointing into evacuation candidate. 3450 SkipList* list = p->skip_list(); 3451 if (list != NULL) list->Clear(); 3452 } else { 3453 if (FLAG_gc_verbose) { 3454 PrintF("Sweeping 0x%" V8PRIxPTR " during evacuation.\n", 3455 reinterpret_cast<intptr_t>(p)); 3456 } 3457 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); 3458 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); 3459 3460 switch (space->identity()) { 3461 case OLD_DATA_SPACE: 3462 SweepConservatively<SWEEP_SEQUENTIALLY>(space, NULL, p); 3463 break; 3464 case OLD_POINTER_SPACE: 3465 SweepPrecisely<SWEEP_AND_VISIT_LIVE_OBJECTS, IGNORE_SKIP_LIST>( 3466 space, p, &updating_visitor); 3467 break; 3468 case CODE_SPACE: 3469 SweepPrecisely<SWEEP_AND_VISIT_LIVE_OBJECTS, REBUILD_SKIP_LIST>( 3470 space, p, &updating_visitor); 3471 break; 3472 default: 3473 UNREACHABLE(); 3474 break; 3475 } 3476 } 3477 } 3478 } 3479 3480 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_UPDATE_MISC_POINTERS); 3481 3482 // Update pointers from cells. 3483 HeapObjectIterator cell_iterator(heap_->cell_space()); 3484 for (HeapObject* cell = cell_iterator.Next(); 3485 cell != NULL; 3486 cell = cell_iterator.Next()) { 3487 if (cell->IsCell()) { 3488 Cell::BodyDescriptor::IterateBody(cell, &updating_visitor); 3489 } 3490 } 3491 3492 HeapObjectIterator js_global_property_cell_iterator( 3493 heap_->property_cell_space()); 3494 for (HeapObject* cell = js_global_property_cell_iterator.Next(); 3495 cell != NULL; 3496 cell = js_global_property_cell_iterator.Next()) { 3497 if (cell->IsPropertyCell()) { 3498 PropertyCell::BodyDescriptor::IterateBody(cell, &updating_visitor); 3499 } 3500 } 3501 3502 // Update the head of the native contexts list in the heap. 3503 updating_visitor.VisitPointer(heap_->native_contexts_list_address()); 3504 3505 heap_->string_table()->Iterate(&updating_visitor); 3506 updating_visitor.VisitPointer(heap_->weak_object_to_code_table_address()); 3507 if (heap_->weak_object_to_code_table()->IsHashTable()) { 3508 WeakHashTable* table = 3509 WeakHashTable::cast(heap_->weak_object_to_code_table()); 3510 table->Iterate(&updating_visitor); 3511 table->Rehash(heap_->undefined_value()); 3512 } 3513 3514 // Update pointers from external string table. 3515 heap_->UpdateReferencesInExternalStringTable( 3516 &UpdateReferenceInExternalStringTableEntry); 3517 3518 if (!FLAG_watch_ic_patching) { 3519 // Update JSFunction pointers from the runtime profiler. 3520 heap()->isolate()->runtime_profiler()->UpdateSamplesAfterCompact( 3521 &updating_visitor); 3522 } 3523 3524 EvacuationWeakObjectRetainer evacuation_object_retainer; 3525 heap()->ProcessWeakReferences(&evacuation_object_retainer); 3526 3527 // Visit invalidated code (we ignored all slots on it) and clear mark-bits 3528 // under it. 3529 ProcessInvalidatedCode(&updating_visitor); 3530 3531 heap_->isolate()->inner_pointer_to_code_cache()->Flush(); 3532 3533 #ifdef VERIFY_HEAP 3534 if (FLAG_verify_heap) { 3535 VerifyEvacuation(heap_); 3536 } 3537 #endif 3538 3539 slots_buffer_allocator_.DeallocateChain(&migration_slots_buffer_); 3540 ASSERT(migration_slots_buffer_ == NULL); 3541 } 3542 3543 3544 void MarkCompactCollector::UnlinkEvacuationCandidates() { 3545 int npages = evacuation_candidates_.length(); 3546 for (int i = 0; i < npages; i++) { 3547 Page* p = evacuation_candidates_[i]; 3548 if (!p->IsEvacuationCandidate()) continue; 3549 p->Unlink(); 3550 p->ClearSweptPrecisely(); 3551 p->ClearSweptConservatively(); 3552 } 3553 } 3554 3555 3556 void MarkCompactCollector::ReleaseEvacuationCandidates() { 3557 int npages = evacuation_candidates_.length(); 3558 for (int i = 0; i < npages; i++) { 3559 Page* p = evacuation_candidates_[i]; 3560 if (!p->IsEvacuationCandidate()) continue; 3561 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); 3562 space->Free(p->area_start(), p->area_size()); 3563 p->set_scan_on_scavenge(false); 3564 slots_buffer_allocator_.DeallocateChain(p->slots_buffer_address()); 3565 p->ResetLiveBytes(); 3566 space->ReleasePage(p, false); 3567 } 3568 evacuation_candidates_.Rewind(0); 3569 compacting_ = false; 3570 heap()->FreeQueuedChunks(); 3571 } 3572 3573 3574 static const int kStartTableEntriesPerLine = 5; 3575 static const int kStartTableLines = 171; 3576 static const int kStartTableInvalidLine = 127; 3577 static const int kStartTableUnusedEntry = 126; 3578 3579 #define _ kStartTableUnusedEntry 3580 #define X kStartTableInvalidLine 3581 // Mark-bit to object start offset table. 3582 // 3583 // The line is indexed by the mark bits in a byte. The first number on 3584 // the line describes the number of live object starts for the line and the 3585 // other numbers on the line describe the offsets (in words) of the object 3586 // starts. 3587 // 3588 // Since objects are at least 2 words large we don't have entries for two 3589 // consecutive 1 bits. All entries after 170 have at least 2 consecutive bits. 3590 char kStartTable[kStartTableLines * kStartTableEntriesPerLine] = { 3591 0, _, _, _, _, // 0 3592 1, 0, _, _, _, // 1 3593 1, 1, _, _, _, // 2 3594 X, _, _, _, _, // 3 3595 1, 2, _, _, _, // 4 3596 2, 0, 2, _, _, // 5 3597 X, _, _, _, _, // 6 3598 X, _, _, _, _, // 7 3599 1, 3, _, _, _, // 8 3600 2, 0, 3, _, _, // 9 3601 2, 1, 3, _, _, // 10 3602 X, _, _, _, _, // 11 3603 X, _, _, _, _, // 12 3604 X, _, _, _, _, // 13 3605 X, _, _, _, _, // 14 3606 X, _, _, _, _, // 15 3607 1, 4, _, _, _, // 16 3608 2, 0, 4, _, _, // 17 3609 2, 1, 4, _, _, // 18 3610 X, _, _, _, _, // 19 3611 2, 2, 4, _, _, // 20 3612 3, 0, 2, 4, _, // 21 3613 X, _, _, _, _, // 22 3614 X, _, _, _, _, // 23 3615 X, _, _, _, _, // 24 3616 X, _, _, _, _, // 25 3617 X, _, _, _, _, // 26 3618 X, _, _, _, _, // 27 3619 X, _, _, _, _, // 28 3620 X, _, _, _, _, // 29 3621 X, _, _, _, _, // 30 3622 X, _, _, _, _, // 31 3623 1, 5, _, _, _, // 32 3624 2, 0, 5, _, _, // 33 3625 2, 1, 5, _, _, // 34 3626 X, _, _, _, _, // 35 3627 2, 2, 5, _, _, // 36 3628 3, 0, 2, 5, _, // 37 3629 X, _, _, _, _, // 38 3630 X, _, _, _, _, // 39 3631 2, 3, 5, _, _, // 40 3632 3, 0, 3, 5, _, // 41 3633 3, 1, 3, 5, _, // 42 3634 X, _, _, _, _, // 43 3635 X, _, _, _, _, // 44 3636 X, _, _, _, _, // 45 3637 X, _, _, _, _, // 46 3638 X, _, _, _, _, // 47 3639 X, _, _, _, _, // 48 3640 X, _, _, _, _, // 49 3641 X, _, _, _, _, // 50 3642 X, _, _, _, _, // 51 3643 X, _, _, _, _, // 52 3644 X, _, _, _, _, // 53 3645 X, _, _, _, _, // 54 3646 X, _, _, _, _, // 55 3647 X, _, _, _, _, // 56 3648 X, _, _, _, _, // 57 3649 X, _, _, _, _, // 58 3650 X, _, _, _, _, // 59 3651 X, _, _, _, _, // 60 3652 X, _, _, _, _, // 61 3653 X, _, _, _, _, // 62 3654 X, _, _, _, _, // 63 3655 1, 6, _, _, _, // 64 3656 2, 0, 6, _, _, // 65 3657 2, 1, 6, _, _, // 66 3658 X, _, _, _, _, // 67 3659 2, 2, 6, _, _, // 68 3660 3, 0, 2, 6, _, // 69 3661 X, _, _, _, _, // 70 3662 X, _, _, _, _, // 71 3663 2, 3, 6, _, _, // 72 3664 3, 0, 3, 6, _, // 73 3665 3, 1, 3, 6, _, // 74 3666 X, _, _, _, _, // 75 3667 X, _, _, _, _, // 76 3668 X, _, _, _, _, // 77 3669 X, _, _, _, _, // 78 3670 X, _, _, _, _, // 79 3671 2, 4, 6, _, _, // 80 3672 3, 0, 4, 6, _, // 81 3673 3, 1, 4, 6, _, // 82 3674 X, _, _, _, _, // 83 3675 3, 2, 4, 6, _, // 84 3676 4, 0, 2, 4, 6, // 85 3677 X, _, _, _, _, // 86 3678 X, _, _, _, _, // 87 3679 X, _, _, _, _, // 88 3680 X, _, _, _, _, // 89 3681 X, _, _, _, _, // 90 3682 X, _, _, _, _, // 91 3683 X, _, _, _, _, // 92 3684 X, _, _, _, _, // 93 3685 X, _, _, _, _, // 94 3686 X, _, _, _, _, // 95 3687 X, _, _, _, _, // 96 3688 X, _, _, _, _, // 97 3689 X, _, _, _, _, // 98 3690 X, _, _, _, _, // 99 3691 X, _, _, _, _, // 100 3692 X, _, _, _, _, // 101 3693 X, _, _, _, _, // 102 3694 X, _, _, _, _, // 103 3695 X, _, _, _, _, // 104 3696 X, _, _, _, _, // 105 3697 X, _, _, _, _, // 106 3698 X, _, _, _, _, // 107 3699 X, _, _, _, _, // 108 3700 X, _, _, _, _, // 109 3701 X, _, _, _, _, // 110 3702 X, _, _, _, _, // 111 3703 X, _, _, _, _, // 112 3704 X, _, _, _, _, // 113 3705 X, _, _, _, _, // 114 3706 X, _, _, _, _, // 115 3707 X, _, _, _, _, // 116 3708 X, _, _, _, _, // 117 3709 X, _, _, _, _, // 118 3710 X, _, _, _, _, // 119 3711 X, _, _, _, _, // 120 3712 X, _, _, _, _, // 121 3713 X, _, _, _, _, // 122 3714 X, _, _, _, _, // 123 3715 X, _, _, _, _, // 124 3716 X, _, _, _, _, // 125 3717 X, _, _, _, _, // 126 3718 X, _, _, _, _, // 127 3719 1, 7, _, _, _, // 128 3720 2, 0, 7, _, _, // 129 3721 2, 1, 7, _, _, // 130 3722 X, _, _, _, _, // 131 3723 2, 2, 7, _, _, // 132 3724 3, 0, 2, 7, _, // 133 3725 X, _, _, _, _, // 134 3726 X, _, _, _, _, // 135 3727 2, 3, 7, _, _, // 136 3728 3, 0, 3, 7, _, // 137 3729 3, 1, 3, 7, _, // 138 3730 X, _, _, _, _, // 139 3731 X, _, _, _, _, // 140 3732 X, _, _, _, _, // 141 3733 X, _, _, _, _, // 142 3734 X, _, _, _, _, // 143 3735 2, 4, 7, _, _, // 144 3736 3, 0, 4, 7, _, // 145 3737 3, 1, 4, 7, _, // 146 3738 X, _, _, _, _, // 147 3739 3, 2, 4, 7, _, // 148 3740 4, 0, 2, 4, 7, // 149 3741 X, _, _, _, _, // 150 3742 X, _, _, _, _, // 151 3743 X, _, _, _, _, // 152 3744 X, _, _, _, _, // 153 3745 X, _, _, _, _, // 154 3746 X, _, _, _, _, // 155 3747 X, _, _, _, _, // 156 3748 X, _, _, _, _, // 157 3749 X, _, _, _, _, // 158 3750 X, _, _, _, _, // 159 3751 2, 5, 7, _, _, // 160 3752 3, 0, 5, 7, _, // 161 3753 3, 1, 5, 7, _, // 162 3754 X, _, _, _, _, // 163 3755 3, 2, 5, 7, _, // 164 3756 4, 0, 2, 5, 7, // 165 3757 X, _, _, _, _, // 166 3758 X, _, _, _, _, // 167 3759 3, 3, 5, 7, _, // 168 3760 4, 0, 3, 5, 7, // 169 3761 4, 1, 3, 5, 7 // 170 3762 }; 3763 #undef _ 3764 #undef X 3765 3766 3767 // Takes a word of mark bits. Returns the number of objects that start in the 3768 // range. Puts the offsets of the words in the supplied array. 3769 static inline int MarkWordToObjectStarts(uint32_t mark_bits, int* starts) { 3770 int objects = 0; 3771 int offset = 0; 3772 3773 // No consecutive 1 bits. 3774 ASSERT((mark_bits & 0x180) != 0x180); 3775 ASSERT((mark_bits & 0x18000) != 0x18000); 3776 ASSERT((mark_bits & 0x1800000) != 0x1800000); 3777 3778 while (mark_bits != 0) { 3779 int byte = (mark_bits & 0xff); 3780 mark_bits >>= 8; 3781 if (byte != 0) { 3782 ASSERT(byte < kStartTableLines); // No consecutive 1 bits. 3783 char* table = kStartTable + byte * kStartTableEntriesPerLine; 3784 int objects_in_these_8_words = table[0]; 3785 ASSERT(objects_in_these_8_words != kStartTableInvalidLine); 3786 ASSERT(objects_in_these_8_words < kStartTableEntriesPerLine); 3787 for (int i = 0; i < objects_in_these_8_words; i++) { 3788 starts[objects++] = offset + table[1 + i]; 3789 } 3790 } 3791 offset += 8; 3792 } 3793 return objects; 3794 } 3795 3796 3797 static inline Address DigestFreeStart(Address approximate_free_start, 3798 uint32_t free_start_cell) { 3799 ASSERT(free_start_cell != 0); 3800 3801 // No consecutive 1 bits. 3802 ASSERT((free_start_cell & (free_start_cell << 1)) == 0); 3803 3804 int offsets[16]; 3805 uint32_t cell = free_start_cell; 3806 int offset_of_last_live; 3807 if ((cell & 0x80000000u) != 0) { 3808 // This case would overflow below. 3809 offset_of_last_live = 31; 3810 } else { 3811 // Remove all but one bit, the most significant. This is an optimization 3812 // that may or may not be worthwhile. 3813 cell |= cell >> 16; 3814 cell |= cell >> 8; 3815 cell |= cell >> 4; 3816 cell |= cell >> 2; 3817 cell |= cell >> 1; 3818 cell = (cell + 1) >> 1; 3819 int live_objects = MarkWordToObjectStarts(cell, offsets); 3820 ASSERT(live_objects == 1); 3821 offset_of_last_live = offsets[live_objects - 1]; 3822 } 3823 Address last_live_start = 3824 approximate_free_start + offset_of_last_live * kPointerSize; 3825 HeapObject* last_live = HeapObject::FromAddress(last_live_start); 3826 Address free_start = last_live_start + last_live->Size(); 3827 return free_start; 3828 } 3829 3830 3831 static inline Address StartOfLiveObject(Address block_address, uint32_t cell) { 3832 ASSERT(cell != 0); 3833 3834 // No consecutive 1 bits. 3835 ASSERT((cell & (cell << 1)) == 0); 3836 3837 int offsets[16]; 3838 if (cell == 0x80000000u) { // Avoid overflow below. 3839 return block_address + 31 * kPointerSize; 3840 } 3841 uint32_t first_set_bit = ((cell ^ (cell - 1)) + 1) >> 1; 3842 ASSERT((first_set_bit & cell) == first_set_bit); 3843 int live_objects = MarkWordToObjectStarts(first_set_bit, offsets); 3844 ASSERT(live_objects == 1); 3845 USE(live_objects); 3846 return block_address + offsets[0] * kPointerSize; 3847 } 3848 3849 3850 template<MarkCompactCollector::SweepingParallelism mode> 3851 static intptr_t Free(PagedSpace* space, 3852 FreeList* free_list, 3853 Address start, 3854 int size) { 3855 if (mode == MarkCompactCollector::SWEEP_SEQUENTIALLY) { 3856 return space->Free(start, size); 3857 } else { 3858 return size - free_list->Free(start, size); 3859 } 3860 } 3861 3862 3863 // Force instantiation of templatized SweepConservatively method for 3864 // SWEEP_SEQUENTIALLY mode. 3865 template intptr_t MarkCompactCollector:: 3866 SweepConservatively<MarkCompactCollector::SWEEP_SEQUENTIALLY>( 3867 PagedSpace*, FreeList*, Page*); 3868 3869 3870 // Force instantiation of templatized SweepConservatively method for 3871 // SWEEP_IN_PARALLEL mode. 3872 template intptr_t MarkCompactCollector:: 3873 SweepConservatively<MarkCompactCollector::SWEEP_IN_PARALLEL>( 3874 PagedSpace*, FreeList*, Page*); 3875 3876 3877 // Sweeps a space conservatively. After this has been done the larger free 3878 // spaces have been put on the free list and the smaller ones have been 3879 // ignored and left untouched. A free space is always either ignored or put 3880 // on the free list, never split up into two parts. This is important 3881 // because it means that any FreeSpace maps left actually describe a region of 3882 // memory that can be ignored when scanning. Dead objects other than free 3883 // spaces will not contain the free space map. 3884 template<MarkCompactCollector::SweepingParallelism mode> 3885 intptr_t MarkCompactCollector::SweepConservatively(PagedSpace* space, 3886 FreeList* free_list, 3887 Page* p) { 3888 ASSERT(!p->IsEvacuationCandidate() && !p->WasSwept()); 3889 ASSERT((mode == MarkCompactCollector::SWEEP_IN_PARALLEL && 3890 free_list != NULL) || 3891 (mode == MarkCompactCollector::SWEEP_SEQUENTIALLY && 3892 free_list == NULL)); 3893 3894 p->MarkSweptConservatively(); 3895 3896 intptr_t freed_bytes = 0; 3897 size_t size = 0; 3898 3899 // Skip over all the dead objects at the start of the page and mark them free. 3900 Address cell_base = 0; 3901 MarkBit::CellType* cell = NULL; 3902 MarkBitCellIterator it(p); 3903 for (; !it.Done(); it.Advance()) { 3904 cell_base = it.CurrentCellBase(); 3905 cell = it.CurrentCell(); 3906 if (*cell != 0) break; 3907 } 3908 3909 if (it.Done()) { 3910 size = p->area_end() - p->area_start(); 3911 freed_bytes += Free<mode>(space, free_list, p->area_start(), 3912 static_cast<int>(size)); 3913 ASSERT_EQ(0, p->LiveBytes()); 3914 return freed_bytes; 3915 } 3916 3917 // Grow the size of the start-of-page free space a little to get up to the 3918 // first live object. 3919 Address free_end = StartOfLiveObject(cell_base, *cell); 3920 // Free the first free space. 3921 size = free_end - p->area_start(); 3922 freed_bytes += Free<mode>(space, free_list, p->area_start(), 3923 static_cast<int>(size)); 3924 3925 // The start of the current free area is represented in undigested form by 3926 // the address of the last 32-word section that contained a live object and 3927 // the marking bitmap for that cell, which describes where the live object 3928 // started. Unless we find a large free space in the bitmap we will not 3929 // digest this pair into a real address. We start the iteration here at the 3930 // first word in the marking bit map that indicates a live object. 3931 Address free_start = cell_base; 3932 MarkBit::CellType free_start_cell = *cell; 3933 3934 for (; !it.Done(); it.Advance()) { 3935 cell_base = it.CurrentCellBase(); 3936 cell = it.CurrentCell(); 3937 if (*cell != 0) { 3938 // We have a live object. Check approximately whether it is more than 32 3939 // words since the last live object. 3940 if (cell_base - free_start > 32 * kPointerSize) { 3941 free_start = DigestFreeStart(free_start, free_start_cell); 3942 if (cell_base - free_start > 32 * kPointerSize) { 3943 // Now that we know the exact start of the free space it still looks 3944 // like we have a large enough free space to be worth bothering with. 3945 // so now we need to find the start of the first live object at the 3946 // end of the free space. 3947 free_end = StartOfLiveObject(cell_base, *cell); 3948 freed_bytes += Free<mode>(space, free_list, free_start, 3949 static_cast<int>(free_end - free_start)); 3950 } 3951 } 3952 // Update our undigested record of where the current free area started. 3953 free_start = cell_base; 3954 free_start_cell = *cell; 3955 // Clear marking bits for current cell. 3956 *cell = 0; 3957 } 3958 } 3959 3960 // Handle the free space at the end of the page. 3961 if (cell_base - free_start > 32 * kPointerSize) { 3962 free_start = DigestFreeStart(free_start, free_start_cell); 3963 freed_bytes += Free<mode>(space, free_list, free_start, 3964 static_cast<int>(p->area_end() - free_start)); 3965 } 3966 3967 p->ResetLiveBytes(); 3968 return freed_bytes; 3969 } 3970 3971 3972 void MarkCompactCollector::SweepInParallel(PagedSpace* space, 3973 FreeList* private_free_list, 3974 FreeList* free_list) { 3975 PageIterator it(space); 3976 while (it.has_next()) { 3977 Page* p = it.next(); 3978 3979 if (p->TryParallelSweeping()) { 3980 SweepConservatively<SWEEP_IN_PARALLEL>(space, private_free_list, p); 3981 free_list->Concatenate(private_free_list); 3982 } 3983 } 3984 } 3985 3986 3987 void MarkCompactCollector::SweepSpace(PagedSpace* space, SweeperType sweeper) { 3988 space->set_was_swept_conservatively(sweeper == CONSERVATIVE || 3989 sweeper == LAZY_CONSERVATIVE || 3990 sweeper == PARALLEL_CONSERVATIVE || 3991 sweeper == CONCURRENT_CONSERVATIVE); 3992 space->ClearStats(); 3993 3994 PageIterator it(space); 3995 3996 int pages_swept = 0; 3997 bool lazy_sweeping_active = false; 3998 bool unused_page_present = false; 3999 bool parallel_sweeping_active = false; 4000 4001 while (it.has_next()) { 4002 Page* p = it.next(); 4003 4004 ASSERT(p->parallel_sweeping() == 0); 4005 ASSERT(!p->IsEvacuationCandidate()); 4006 4007 // Clear sweeping flags indicating that marking bits are still intact. 4008 p->ClearSweptPrecisely(); 4009 p->ClearSweptConservatively(); 4010 4011 if (p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) { 4012 // Will be processed in EvacuateNewSpaceAndCandidates. 4013 ASSERT(evacuation_candidates_.length() > 0); 4014 continue; 4015 } 4016 4017 // One unused page is kept, all further are released before sweeping them. 4018 if (p->LiveBytes() == 0) { 4019 if (unused_page_present) { 4020 if (FLAG_gc_verbose) { 4021 PrintF("Sweeping 0x%" V8PRIxPTR " released page.\n", 4022 reinterpret_cast<intptr_t>(p)); 4023 } 4024 // Adjust unswept free bytes because releasing a page expects said 4025 // counter to be accurate for unswept pages. 4026 space->IncreaseUnsweptFreeBytes(p); 4027 space->ReleasePage(p, true); 4028 continue; 4029 } 4030 unused_page_present = true; 4031 } 4032 4033 switch (sweeper) { 4034 case CONSERVATIVE: { 4035 if (FLAG_gc_verbose) { 4036 PrintF("Sweeping 0x%" V8PRIxPTR " conservatively.\n", 4037 reinterpret_cast<intptr_t>(p)); 4038 } 4039 SweepConservatively<SWEEP_SEQUENTIALLY>(space, NULL, p); 4040 pages_swept++; 4041 break; 4042 } 4043 case LAZY_CONSERVATIVE: { 4044 if (lazy_sweeping_active) { 4045 if (FLAG_gc_verbose) { 4046 PrintF("Sweeping 0x%" V8PRIxPTR " lazily postponed.\n", 4047 reinterpret_cast<intptr_t>(p)); 4048 } 4049 space->IncreaseUnsweptFreeBytes(p); 4050 } else { 4051 if (FLAG_gc_verbose) { 4052 PrintF("Sweeping 0x%" V8PRIxPTR " conservatively.\n", 4053 reinterpret_cast<intptr_t>(p)); 4054 } 4055 SweepConservatively<SWEEP_SEQUENTIALLY>(space, NULL, p); 4056 pages_swept++; 4057 space->SetPagesToSweep(p->next_page()); 4058 lazy_sweeping_active = true; 4059 } 4060 break; 4061 } 4062 case CONCURRENT_CONSERVATIVE: 4063 case PARALLEL_CONSERVATIVE: { 4064 if (!parallel_sweeping_active) { 4065 if (FLAG_gc_verbose) { 4066 PrintF("Sweeping 0x%" V8PRIxPTR " conservatively.\n", 4067 reinterpret_cast<intptr_t>(p)); 4068 } 4069 SweepConservatively<SWEEP_SEQUENTIALLY>(space, NULL, p); 4070 pages_swept++; 4071 parallel_sweeping_active = true; 4072 } else { 4073 if (FLAG_gc_verbose) { 4074 PrintF("Sweeping 0x%" V8PRIxPTR " conservatively in parallel.\n", 4075 reinterpret_cast<intptr_t>(p)); 4076 } 4077 p->set_parallel_sweeping(1); 4078 space->IncreaseUnsweptFreeBytes(p); 4079 } 4080 break; 4081 } 4082 case PRECISE: { 4083 if (FLAG_gc_verbose) { 4084 PrintF("Sweeping 0x%" V8PRIxPTR " precisely.\n", 4085 reinterpret_cast<intptr_t>(p)); 4086 } 4087 if (space->identity() == CODE_SPACE) { 4088 SweepPrecisely<SWEEP_ONLY, REBUILD_SKIP_LIST>(space, p, NULL); 4089 } else { 4090 SweepPrecisely<SWEEP_ONLY, IGNORE_SKIP_LIST>(space, p, NULL); 4091 } 4092 pages_swept++; 4093 break; 4094 } 4095 default: { 4096 UNREACHABLE(); 4097 } 4098 } 4099 } 4100 4101 if (FLAG_gc_verbose) { 4102 PrintF("SweepSpace: %s (%d pages swept)\n", 4103 AllocationSpaceName(space->identity()), 4104 pages_swept); 4105 } 4106 4107 // Give pages that are queued to be freed back to the OS. 4108 heap()->FreeQueuedChunks(); 4109 } 4110 4111 4112 void MarkCompactCollector::SweepSpaces() { 4113 GCTracer::Scope gc_scope(tracer_, GCTracer::Scope::MC_SWEEP); 4114 #ifdef DEBUG 4115 state_ = SWEEP_SPACES; 4116 #endif 4117 SweeperType how_to_sweep = 4118 FLAG_lazy_sweeping ? LAZY_CONSERVATIVE : CONSERVATIVE; 4119 if (isolate()->num_sweeper_threads() > 0) { 4120 if (FLAG_parallel_sweeping) how_to_sweep = PARALLEL_CONSERVATIVE; 4121 if (FLAG_concurrent_sweeping) how_to_sweep = CONCURRENT_CONSERVATIVE; 4122 } 4123 if (FLAG_expose_gc) how_to_sweep = CONSERVATIVE; 4124 if (sweep_precisely_) how_to_sweep = PRECISE; 4125 4126 // Unlink evacuation candidates before sweeper threads access the list of 4127 // pages to avoid race condition. 4128 UnlinkEvacuationCandidates(); 4129 4130 // Noncompacting collections simply sweep the spaces to clear the mark 4131 // bits and free the nonlive blocks (for old and map spaces). We sweep 4132 // the map space last because freeing non-live maps overwrites them and 4133 // the other spaces rely on possibly non-live maps to get the sizes for 4134 // non-live objects. 4135 SequentialSweepingScope scope(this); 4136 SweepSpace(heap()->old_pointer_space(), how_to_sweep); 4137 SweepSpace(heap()->old_data_space(), how_to_sweep); 4138 4139 if (how_to_sweep == PARALLEL_CONSERVATIVE || 4140 how_to_sweep == CONCURRENT_CONSERVATIVE) { 4141 // TODO(hpayer): fix race with concurrent sweeper 4142 StartSweeperThreads(); 4143 } 4144 4145 if (how_to_sweep == PARALLEL_CONSERVATIVE) { 4146 WaitUntilSweepingCompleted(); 4147 } 4148 4149 RemoveDeadInvalidatedCode(); 4150 SweepSpace(heap()->code_space(), PRECISE); 4151 4152 SweepSpace(heap()->cell_space(), PRECISE); 4153 SweepSpace(heap()->property_cell_space(), PRECISE); 4154 4155 EvacuateNewSpaceAndCandidates(); 4156 4157 // ClearNonLiveTransitions depends on precise sweeping of map space to 4158 // detect whether unmarked map became dead in this collection or in one 4159 // of the previous ones. 4160 SweepSpace(heap()->map_space(), PRECISE); 4161 4162 // Deallocate unmarked objects and clear marked bits for marked objects. 4163 heap_->lo_space()->FreeUnmarkedObjects(); 4164 4165 // Deallocate evacuated candidate pages. 4166 ReleaseEvacuationCandidates(); 4167 } 4168 4169 4170 void MarkCompactCollector::EnableCodeFlushing(bool enable) { 4171 #ifdef ENABLE_DEBUGGER_SUPPORT 4172 if (isolate()->debug()->IsLoaded() || 4173 isolate()->debug()->has_break_points()) { 4174 enable = false; 4175 } 4176 #endif 4177 4178 if (enable) { 4179 if (code_flusher_ != NULL) return; 4180 code_flusher_ = new CodeFlusher(isolate()); 4181 } else { 4182 if (code_flusher_ == NULL) return; 4183 code_flusher_->EvictAllCandidates(); 4184 delete code_flusher_; 4185 code_flusher_ = NULL; 4186 } 4187 4188 if (FLAG_trace_code_flushing) { 4189 PrintF("[code-flushing is now %s]\n", enable ? "on" : "off"); 4190 } 4191 } 4192 4193 4194 // TODO(1466) ReportDeleteIfNeeded is not called currently. 4195 // Our profiling tools do not expect intersections between 4196 // code objects. We should either reenable it or change our tools. 4197 void MarkCompactCollector::ReportDeleteIfNeeded(HeapObject* obj, 4198 Isolate* isolate) { 4199 #ifdef ENABLE_GDB_JIT_INTERFACE 4200 if (obj->IsCode()) { 4201 GDBJITInterface::RemoveCode(reinterpret_cast<Code*>(obj)); 4202 } 4203 #endif 4204 if (obj->IsCode()) { 4205 PROFILE(isolate, CodeDeleteEvent(obj->address())); 4206 } 4207 } 4208 4209 4210 Isolate* MarkCompactCollector::isolate() const { 4211 return heap_->isolate(); 4212 } 4213 4214 4215 void MarkCompactCollector::Initialize() { 4216 MarkCompactMarkingVisitor::Initialize(); 4217 IncrementalMarking::Initialize(); 4218 } 4219 4220 4221 bool SlotsBuffer::IsTypedSlot(ObjectSlot slot) { 4222 return reinterpret_cast<uintptr_t>(slot) < NUMBER_OF_SLOT_TYPES; 4223 } 4224 4225 4226 bool SlotsBuffer::AddTo(SlotsBufferAllocator* allocator, 4227 SlotsBuffer** buffer_address, 4228 SlotType type, 4229 Address addr, 4230 AdditionMode mode) { 4231 SlotsBuffer* buffer = *buffer_address; 4232 if (buffer == NULL || !buffer->HasSpaceForTypedSlot()) { 4233 if (mode == FAIL_ON_OVERFLOW && ChainLengthThresholdReached(buffer)) { 4234 allocator->DeallocateChain(buffer_address); 4235 return false; 4236 } 4237 buffer = allocator->AllocateBuffer(buffer); 4238 *buffer_address = buffer; 4239 } 4240 ASSERT(buffer->HasSpaceForTypedSlot()); 4241 buffer->Add(reinterpret_cast<ObjectSlot>(type)); 4242 buffer->Add(reinterpret_cast<ObjectSlot>(addr)); 4243 return true; 4244 } 4245 4246 4247 static inline SlotsBuffer::SlotType SlotTypeForRMode(RelocInfo::Mode rmode) { 4248 if (RelocInfo::IsCodeTarget(rmode)) { 4249 return SlotsBuffer::CODE_TARGET_SLOT; 4250 } else if (RelocInfo::IsEmbeddedObject(rmode)) { 4251 return SlotsBuffer::EMBEDDED_OBJECT_SLOT; 4252 } else if (RelocInfo::IsDebugBreakSlot(rmode)) { 4253 return SlotsBuffer::DEBUG_TARGET_SLOT; 4254 } else if (RelocInfo::IsJSReturn(rmode)) { 4255 return SlotsBuffer::JS_RETURN_SLOT; 4256 } 4257 UNREACHABLE(); 4258 return SlotsBuffer::NUMBER_OF_SLOT_TYPES; 4259 } 4260 4261 4262 void MarkCompactCollector::RecordRelocSlot(RelocInfo* rinfo, Object* target) { 4263 Page* target_page = Page::FromAddress(reinterpret_cast<Address>(target)); 4264 if (target_page->IsEvacuationCandidate() && 4265 (rinfo->host() == NULL || 4266 !ShouldSkipEvacuationSlotRecording(rinfo->host()))) { 4267 if (!SlotsBuffer::AddTo(&slots_buffer_allocator_, 4268 target_page->slots_buffer_address(), 4269 SlotTypeForRMode(rinfo->rmode()), 4270 rinfo->pc(), 4271 SlotsBuffer::FAIL_ON_OVERFLOW)) { 4272 EvictEvacuationCandidate(target_page); 4273 } 4274 } 4275 } 4276 4277 4278 void MarkCompactCollector::RecordCodeEntrySlot(Address slot, Code* target) { 4279 Page* target_page = Page::FromAddress(reinterpret_cast<Address>(target)); 4280 if (target_page->IsEvacuationCandidate() && 4281 !ShouldSkipEvacuationSlotRecording(reinterpret_cast<Object**>(slot))) { 4282 if (!SlotsBuffer::AddTo(&slots_buffer_allocator_, 4283 target_page->slots_buffer_address(), 4284 SlotsBuffer::CODE_ENTRY_SLOT, 4285 slot, 4286 SlotsBuffer::FAIL_ON_OVERFLOW)) { 4287 EvictEvacuationCandidate(target_page); 4288 } 4289 } 4290 } 4291 4292 4293 void MarkCompactCollector::RecordCodeTargetPatch(Address pc, Code* target) { 4294 ASSERT(heap()->gc_state() == Heap::MARK_COMPACT); 4295 if (is_compacting()) { 4296 Code* host = isolate()->inner_pointer_to_code_cache()-> 4297 GcSafeFindCodeForInnerPointer(pc); 4298 MarkBit mark_bit = Marking::MarkBitFrom(host); 4299 if (Marking::IsBlack(mark_bit)) { 4300 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); 4301 RecordRelocSlot(&rinfo, target); 4302 } 4303 } 4304 } 4305 4306 4307 static inline SlotsBuffer::SlotType DecodeSlotType( 4308 SlotsBuffer::ObjectSlot slot) { 4309 return static_cast<SlotsBuffer::SlotType>(reinterpret_cast<intptr_t>(slot)); 4310 } 4311 4312 4313 void SlotsBuffer::UpdateSlots(Heap* heap) { 4314 PointersUpdatingVisitor v(heap); 4315 4316 for (int slot_idx = 0; slot_idx < idx_; ++slot_idx) { 4317 ObjectSlot slot = slots_[slot_idx]; 4318 if (!IsTypedSlot(slot)) { 4319 PointersUpdatingVisitor::UpdateSlot(heap, slot); 4320 } else { 4321 ++slot_idx; 4322 ASSERT(slot_idx < idx_); 4323 UpdateSlot(heap->isolate(), 4324 &v, 4325 DecodeSlotType(slot), 4326 reinterpret_cast<Address>(slots_[slot_idx])); 4327 } 4328 } 4329 } 4330 4331 4332 void SlotsBuffer::UpdateSlotsWithFilter(Heap* heap) { 4333 PointersUpdatingVisitor v(heap); 4334 4335 for (int slot_idx = 0; slot_idx < idx_; ++slot_idx) { 4336 ObjectSlot slot = slots_[slot_idx]; 4337 if (!IsTypedSlot(slot)) { 4338 if (!IsOnInvalidatedCodeObject(reinterpret_cast<Address>(slot))) { 4339 PointersUpdatingVisitor::UpdateSlot(heap, slot); 4340 } 4341 } else { 4342 ++slot_idx; 4343 ASSERT(slot_idx < idx_); 4344 Address pc = reinterpret_cast<Address>(slots_[slot_idx]); 4345 if (!IsOnInvalidatedCodeObject(pc)) { 4346 UpdateSlot(heap->isolate(), 4347 &v, 4348 DecodeSlotType(slot), 4349 reinterpret_cast<Address>(slots_[slot_idx])); 4350 } 4351 } 4352 } 4353 } 4354 4355 4356 SlotsBuffer* SlotsBufferAllocator::AllocateBuffer(SlotsBuffer* next_buffer) { 4357 return new SlotsBuffer(next_buffer); 4358 } 4359 4360 4361 void SlotsBufferAllocator::DeallocateBuffer(SlotsBuffer* buffer) { 4362 delete buffer; 4363 } 4364 4365 4366 void SlotsBufferAllocator::DeallocateChain(SlotsBuffer** buffer_address) { 4367 SlotsBuffer* buffer = *buffer_address; 4368 while (buffer != NULL) { 4369 SlotsBuffer* next_buffer = buffer->next(); 4370 DeallocateBuffer(buffer); 4371 buffer = next_buffer; 4372 } 4373 *buffer_address = NULL; 4374 } 4375 4376 4377 } } // namespace v8::internal 4378