1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/heap/incremental-marking.h" 6 7 #include "src/code-stubs.h" 8 #include "src/compilation-cache.h" 9 #include "src/conversions.h" 10 #include "src/heap/gc-idle-time-handler.h" 11 #include "src/heap/gc-tracer.h" 12 #include "src/heap/mark-compact-inl.h" 13 #include "src/heap/object-stats.h" 14 #include "src/heap/objects-visiting-inl.h" 15 #include "src/heap/objects-visiting.h" 16 #include "src/tracing/trace-event.h" 17 #include "src/v8.h" 18 19 namespace v8 { 20 namespace internal { 21 22 IncrementalMarking::StepActions IncrementalMarking::IdleStepActions() { 23 return StepActions(IncrementalMarking::NO_GC_VIA_STACK_GUARD, 24 IncrementalMarking::FORCE_MARKING, 25 IncrementalMarking::DO_NOT_FORCE_COMPLETION); 26 } 27 28 IncrementalMarking::IncrementalMarking(Heap* heap) 29 : heap_(heap), 30 observer_(*this, kAllocatedThreshold), 31 state_(STOPPED), 32 is_compacting_(false), 33 steps_count_(0), 34 old_generation_space_available_at_start_of_incremental_(0), 35 old_generation_space_used_at_start_of_incremental_(0), 36 bytes_rescanned_(0), 37 should_hurry_(false), 38 marking_speed_(0), 39 bytes_scanned_(0), 40 allocated_(0), 41 write_barriers_invoked_since_last_step_(0), 42 idle_marking_delay_counter_(0), 43 unscanned_bytes_of_large_object_(0), 44 was_activated_(false), 45 black_allocation_(false), 46 finalize_marking_completed_(false), 47 incremental_marking_finalization_rounds_(0), 48 request_type_(NONE) {} 49 50 bool IncrementalMarking::BaseRecordWrite(HeapObject* obj, Object* value) { 51 HeapObject* value_heap_obj = HeapObject::cast(value); 52 MarkBit value_bit = Marking::MarkBitFrom(value_heap_obj); 53 DCHECK(!Marking::IsImpossible(value_bit)); 54 55 MarkBit obj_bit = Marking::MarkBitFrom(obj); 56 DCHECK(!Marking::IsImpossible(obj_bit)); 57 bool is_black = Marking::IsBlack(obj_bit); 58 59 if (is_black && Marking::IsWhite(value_bit)) { 60 WhiteToGreyAndPush(value_heap_obj, value_bit); 61 RestartIfNotMarking(); 62 } 63 return is_compacting_ && is_black; 64 } 65 66 67 void IncrementalMarking::RecordWriteSlow(HeapObject* obj, Object** slot, 68 Object* value) { 69 if (BaseRecordWrite(obj, value) && slot != NULL) { 70 // Object is not going to be rescanned we need to record the slot. 71 heap_->mark_compact_collector()->RecordSlot(obj, slot, value); 72 } 73 } 74 75 76 void IncrementalMarking::RecordWriteFromCode(HeapObject* obj, Object** slot, 77 Isolate* isolate) { 78 DCHECK(obj->IsHeapObject()); 79 IncrementalMarking* marking = isolate->heap()->incremental_marking(); 80 81 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); 82 int counter = chunk->write_barrier_counter(); 83 if (counter < (MemoryChunk::kWriteBarrierCounterGranularity / 2)) { 84 marking->write_barriers_invoked_since_last_step_ += 85 MemoryChunk::kWriteBarrierCounterGranularity - 86 chunk->write_barrier_counter(); 87 chunk->set_write_barrier_counter( 88 MemoryChunk::kWriteBarrierCounterGranularity); 89 } 90 91 marking->RecordWrite(obj, slot, *slot); 92 } 93 94 // static 95 void IncrementalMarking::RecordWriteOfCodeEntryFromCode(JSFunction* host, 96 Object** slot, 97 Isolate* isolate) { 98 DCHECK(host->IsJSFunction()); 99 IncrementalMarking* marking = isolate->heap()->incremental_marking(); 100 Code* value = Code::cast( 101 Code::GetObjectFromEntryAddress(reinterpret_cast<Address>(slot))); 102 marking->RecordWriteOfCodeEntry(host, slot, value); 103 } 104 105 void IncrementalMarking::RecordCodeTargetPatch(Code* host, Address pc, 106 HeapObject* value) { 107 if (IsMarking()) { 108 RelocInfo rinfo(heap_->isolate(), pc, RelocInfo::CODE_TARGET, 0, host); 109 RecordWriteIntoCode(host, &rinfo, value); 110 } 111 } 112 113 114 void IncrementalMarking::RecordCodeTargetPatch(Address pc, HeapObject* value) { 115 if (IsMarking()) { 116 Code* host = heap_->isolate() 117 ->inner_pointer_to_code_cache() 118 ->GcSafeFindCodeForInnerPointer(pc); 119 RelocInfo rinfo(heap_->isolate(), pc, RelocInfo::CODE_TARGET, 0, host); 120 RecordWriteIntoCode(host, &rinfo, value); 121 } 122 } 123 124 125 void IncrementalMarking::RecordWriteOfCodeEntrySlow(JSFunction* host, 126 Object** slot, 127 Code* value) { 128 if (BaseRecordWrite(host, value)) { 129 DCHECK(slot != NULL); 130 heap_->mark_compact_collector()->RecordCodeEntrySlot( 131 host, reinterpret_cast<Address>(slot), value); 132 } 133 } 134 135 void IncrementalMarking::RecordWriteIntoCodeSlow(Code* host, RelocInfo* rinfo, 136 Object* value) { 137 if (BaseRecordWrite(host, value)) { 138 // Object is not going to be rescanned. We need to record the slot. 139 heap_->mark_compact_collector()->RecordRelocSlot(host, rinfo, value); 140 } 141 } 142 143 144 void IncrementalMarking::WhiteToGreyAndPush(HeapObject* obj, MarkBit mark_bit) { 145 Marking::WhiteToGrey(mark_bit); 146 heap_->mark_compact_collector()->marking_deque()->Push(obj); 147 } 148 149 150 static void MarkObjectGreyDoNotEnqueue(Object* obj) { 151 if (obj->IsHeapObject()) { 152 HeapObject* heap_obj = HeapObject::cast(obj); 153 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::cast(obj)); 154 if (Marking::IsBlack(mark_bit)) { 155 MemoryChunk::IncrementLiveBytesFromGC(heap_obj, -heap_obj->Size()); 156 } 157 Marking::AnyToGrey(mark_bit); 158 } 159 } 160 161 162 static inline void MarkBlackOrKeepBlack(HeapObject* heap_object, 163 MarkBit mark_bit, int size) { 164 DCHECK(!Marking::IsImpossible(mark_bit)); 165 if (Marking::IsBlack(mark_bit)) return; 166 Marking::MarkBlack(mark_bit); 167 MemoryChunk::IncrementLiveBytesFromGC(heap_object, size); 168 } 169 170 171 class IncrementalMarkingMarkingVisitor 172 : public StaticMarkingVisitor<IncrementalMarkingMarkingVisitor> { 173 public: 174 static void Initialize() { 175 StaticMarkingVisitor<IncrementalMarkingMarkingVisitor>::Initialize(); 176 table_.Register(kVisitFixedArray, &VisitFixedArrayIncremental); 177 table_.Register(kVisitNativeContext, &VisitNativeContextIncremental); 178 table_.Register(kVisitJSRegExp, &VisitJSRegExp); 179 if (FLAG_track_gc_object_stats) { 180 IncrementalMarkingObjectStatsVisitor::Initialize(&table_); 181 } 182 } 183 184 static const int kProgressBarScanningChunk = 32 * 1024; 185 186 static void VisitFixedArrayIncremental(Map* map, HeapObject* object) { 187 MemoryChunk* chunk = MemoryChunk::FromAddress(object->address()); 188 // TODO(mstarzinger): Move setting of the flag to the allocation site of 189 // the array. The visitor should just check the flag. 190 if (FLAG_use_marking_progress_bar && 191 chunk->owner()->identity() == LO_SPACE) { 192 chunk->SetFlag(MemoryChunk::HAS_PROGRESS_BAR); 193 } 194 if (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) { 195 Heap* heap = map->GetHeap(); 196 // When using a progress bar for large fixed arrays, scan only a chunk of 197 // the array and try to push it onto the marking deque again until it is 198 // fully scanned. Fall back to scanning it through to the end in case this 199 // fails because of a full deque. 200 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object); 201 int start_offset = 202 Max(FixedArray::BodyDescriptor::kStartOffset, chunk->progress_bar()); 203 int end_offset = 204 Min(object_size, start_offset + kProgressBarScanningChunk); 205 int already_scanned_offset = start_offset; 206 bool scan_until_end = false; 207 do { 208 VisitPointers(heap, object, HeapObject::RawField(object, start_offset), 209 HeapObject::RawField(object, end_offset)); 210 start_offset = end_offset; 211 end_offset = Min(object_size, end_offset + kProgressBarScanningChunk); 212 scan_until_end = 213 heap->mark_compact_collector()->marking_deque()->IsFull(); 214 } while (scan_until_end && start_offset < object_size); 215 chunk->set_progress_bar(start_offset); 216 if (start_offset < object_size) { 217 if (Marking::IsGrey(Marking::MarkBitFrom(object))) { 218 heap->mark_compact_collector()->marking_deque()->Unshift(object); 219 } else { 220 DCHECK(Marking::IsBlack(Marking::MarkBitFrom(object))); 221 heap->mark_compact_collector()->UnshiftBlack(object); 222 } 223 heap->incremental_marking()->NotifyIncompleteScanOfObject( 224 object_size - (start_offset - already_scanned_offset)); 225 } 226 } else { 227 FixedArrayVisitor::Visit(map, object); 228 } 229 } 230 231 static void VisitNativeContextIncremental(Map* map, HeapObject* object) { 232 Context* context = Context::cast(object); 233 234 // We will mark cache black with a separate pass when we finish marking. 235 // Note that GC can happen when the context is not fully initialized, 236 // so the cache can be undefined. 237 Object* cache = context->get(Context::NORMALIZED_MAP_CACHE_INDEX); 238 if (!cache->IsUndefined(map->GetIsolate())) { 239 MarkObjectGreyDoNotEnqueue(cache); 240 } 241 VisitNativeContext(map, context); 242 } 243 244 INLINE(static void VisitPointer(Heap* heap, HeapObject* object, Object** p)) { 245 Object* target = *p; 246 if (target->IsHeapObject()) { 247 heap->mark_compact_collector()->RecordSlot(object, p, target); 248 MarkObject(heap, target); 249 } 250 } 251 252 INLINE(static void VisitPointers(Heap* heap, HeapObject* object, 253 Object** start, Object** end)) { 254 for (Object** p = start; p < end; p++) { 255 Object* target = *p; 256 if (target->IsHeapObject()) { 257 heap->mark_compact_collector()->RecordSlot(object, p, target); 258 MarkObject(heap, target); 259 } 260 } 261 } 262 263 // Marks the object grey and pushes it on the marking stack. 264 INLINE(static void MarkObject(Heap* heap, Object* obj)) { 265 IncrementalMarking::MarkObject(heap, HeapObject::cast(obj)); 266 } 267 268 // Marks the object black without pushing it on the marking stack. 269 // Returns true if object needed marking and false otherwise. 270 INLINE(static bool MarkObjectWithoutPush(Heap* heap, Object* obj)) { 271 HeapObject* heap_object = HeapObject::cast(obj); 272 MarkBit mark_bit = Marking::MarkBitFrom(heap_object); 273 if (Marking::IsWhite(mark_bit)) { 274 Marking::MarkBlack(mark_bit); 275 MemoryChunk::IncrementLiveBytesFromGC(heap_object, heap_object->Size()); 276 return true; 277 } 278 return false; 279 } 280 }; 281 282 void IncrementalMarking::IterateBlackObject(HeapObject* object) { 283 if (IsMarking() && Marking::IsBlack(Marking::MarkBitFrom(object))) { 284 Page* page = Page::FromAddress(object->address()); 285 if ((page->owner() != nullptr) && (page->owner()->identity() == LO_SPACE)) { 286 // IterateBlackObject requires us to visit the whole object. 287 page->ResetProgressBar(); 288 } 289 IncrementalMarkingMarkingVisitor::IterateBody(object->map(), object); 290 } 291 } 292 293 class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor { 294 public: 295 explicit IncrementalMarkingRootMarkingVisitor( 296 IncrementalMarking* incremental_marking) 297 : heap_(incremental_marking->heap()) {} 298 299 void VisitPointer(Object** p) override { MarkObjectByPointer(p); } 300 301 void VisitPointers(Object** start, Object** end) override { 302 for (Object** p = start; p < end; p++) MarkObjectByPointer(p); 303 } 304 305 private: 306 void MarkObjectByPointer(Object** p) { 307 Object* obj = *p; 308 if (!obj->IsHeapObject()) return; 309 310 IncrementalMarking::MarkObject(heap_, HeapObject::cast(obj)); 311 } 312 313 Heap* heap_; 314 }; 315 316 317 void IncrementalMarking::Initialize() { 318 IncrementalMarkingMarkingVisitor::Initialize(); 319 } 320 321 322 void IncrementalMarking::SetOldSpacePageFlags(MemoryChunk* chunk, 323 bool is_marking, 324 bool is_compacting) { 325 if (is_marking) { 326 chunk->SetFlag(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING); 327 chunk->SetFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING); 328 } else { 329 chunk->ClearFlag(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING); 330 chunk->SetFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING); 331 } 332 } 333 334 335 void IncrementalMarking::SetNewSpacePageFlags(MemoryChunk* chunk, 336 bool is_marking) { 337 chunk->SetFlag(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING); 338 if (is_marking) { 339 chunk->SetFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING); 340 } else { 341 chunk->ClearFlag(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING); 342 } 343 } 344 345 346 void IncrementalMarking::DeactivateIncrementalWriteBarrierForSpace( 347 PagedSpace* space) { 348 for (Page* p : *space) { 349 SetOldSpacePageFlags(p, false, false); 350 } 351 } 352 353 354 void IncrementalMarking::DeactivateIncrementalWriteBarrierForSpace( 355 NewSpace* space) { 356 for (Page* p : *space) { 357 SetNewSpacePageFlags(p, false); 358 } 359 } 360 361 362 void IncrementalMarking::DeactivateIncrementalWriteBarrier() { 363 DeactivateIncrementalWriteBarrierForSpace(heap_->old_space()); 364 DeactivateIncrementalWriteBarrierForSpace(heap_->map_space()); 365 DeactivateIncrementalWriteBarrierForSpace(heap_->code_space()); 366 DeactivateIncrementalWriteBarrierForSpace(heap_->new_space()); 367 368 for (LargePage* lop : *heap_->lo_space()) { 369 SetOldSpacePageFlags(lop, false, false); 370 } 371 } 372 373 374 void IncrementalMarking::ActivateIncrementalWriteBarrier(PagedSpace* space) { 375 for (Page* p : *space) { 376 SetOldSpacePageFlags(p, true, is_compacting_); 377 } 378 } 379 380 381 void IncrementalMarking::ActivateIncrementalWriteBarrier(NewSpace* space) { 382 for (Page* p : *space) { 383 SetNewSpacePageFlags(p, true); 384 } 385 } 386 387 388 void IncrementalMarking::ActivateIncrementalWriteBarrier() { 389 ActivateIncrementalWriteBarrier(heap_->old_space()); 390 ActivateIncrementalWriteBarrier(heap_->map_space()); 391 ActivateIncrementalWriteBarrier(heap_->code_space()); 392 ActivateIncrementalWriteBarrier(heap_->new_space()); 393 394 for (LargePage* lop : *heap_->lo_space()) { 395 SetOldSpacePageFlags(lop, true, is_compacting_); 396 } 397 } 398 399 400 bool IncrementalMarking::ShouldActivateEvenWithoutIdleNotification() { 401 #ifndef DEBUG 402 static const intptr_t kActivationThreshold = 8 * MB; 403 #else 404 // TODO(gc) consider setting this to some low level so that some 405 // debug tests run with incremental marking and some without. 406 static const intptr_t kActivationThreshold = 0; 407 #endif 408 // Don't switch on for very small heaps. 409 return CanBeActivated() && 410 heap_->PromotedSpaceSizeOfObjects() > kActivationThreshold && 411 heap_->HeapIsFullEnoughToStartIncrementalMarking( 412 heap_->old_generation_allocation_limit()); 413 } 414 415 416 bool IncrementalMarking::WasActivated() { return was_activated_; } 417 418 419 bool IncrementalMarking::CanBeActivated() { 420 // Only start incremental marking in a safe state: 1) when incremental 421 // marking is turned on, 2) when we are currently not in a GC, and 422 // 3) when we are currently not serializing or deserializing the heap. 423 return FLAG_incremental_marking && heap_->gc_state() == Heap::NOT_IN_GC && 424 heap_->deserialization_complete() && 425 !heap_->isolate()->serializer_enabled(); 426 } 427 428 429 void IncrementalMarking::ActivateGeneratedStub(Code* stub) { 430 DCHECK(RecordWriteStub::GetMode(stub) == RecordWriteStub::STORE_BUFFER_ONLY); 431 432 if (!IsMarking()) { 433 // Initially stub is generated in STORE_BUFFER_ONLY mode thus 434 // we don't need to do anything if incremental marking is 435 // not active. 436 } else if (IsCompacting()) { 437 RecordWriteStub::Patch(stub, RecordWriteStub::INCREMENTAL_COMPACTION); 438 } else { 439 RecordWriteStub::Patch(stub, RecordWriteStub::INCREMENTAL); 440 } 441 } 442 443 444 void IncrementalMarking::NotifyOfHighPromotionRate() { 445 if (IsMarking()) { 446 if (marking_speed_ < kFastMarking) { 447 if (FLAG_trace_gc) { 448 PrintIsolate(heap()->isolate(), 449 "Increasing marking speed to %d " 450 "due to high promotion rate\n", 451 static_cast<int>(kFastMarking)); 452 } 453 marking_speed_ = kFastMarking; 454 } 455 } 456 } 457 458 459 static void PatchIncrementalMarkingRecordWriteStubs( 460 Heap* heap, RecordWriteStub::Mode mode) { 461 UnseededNumberDictionary* stubs = heap->code_stubs(); 462 463 int capacity = stubs->Capacity(); 464 Isolate* isolate = heap->isolate(); 465 for (int i = 0; i < capacity; i++) { 466 Object* k = stubs->KeyAt(i); 467 if (stubs->IsKey(isolate, k)) { 468 uint32_t key = NumberToUint32(k); 469 470 if (CodeStub::MajorKeyFromKey(key) == CodeStub::RecordWrite) { 471 Object* e = stubs->ValueAt(i); 472 if (e->IsCode()) { 473 RecordWriteStub::Patch(Code::cast(e), mode); 474 } 475 } 476 } 477 } 478 } 479 480 481 void IncrementalMarking::Start(const char* reason) { 482 if (FLAG_trace_incremental_marking) { 483 PrintF("[IncrementalMarking] Start (%s)\n", 484 (reason == nullptr) ? "unknown reason" : reason); 485 } 486 DCHECK(FLAG_incremental_marking); 487 DCHECK(state_ == STOPPED); 488 DCHECK(heap_->gc_state() == Heap::NOT_IN_GC); 489 DCHECK(!heap_->isolate()->serializer_enabled()); 490 491 HistogramTimerScope incremental_marking_scope( 492 heap_->isolate()->counters()->gc_incremental_marking_start()); 493 TRACE_EVENT0("v8", "V8.GCIncrementalMarkingStart"); 494 ResetStepCounters(); 495 496 was_activated_ = true; 497 498 if (!heap_->mark_compact_collector()->sweeping_in_progress()) { 499 StartMarking(); 500 } else { 501 if (FLAG_trace_incremental_marking) { 502 PrintF("[IncrementalMarking] Start sweeping.\n"); 503 } 504 state_ = SWEEPING; 505 } 506 507 heap_->new_space()->AddAllocationObserver(&observer_); 508 509 incremental_marking_job()->Start(heap_); 510 } 511 512 513 void IncrementalMarking::StartMarking() { 514 if (heap_->isolate()->serializer_enabled()) { 515 // Black allocation currently starts when we start incremental marking, 516 // but we cannot enable black allocation while deserializing. Hence, we 517 // have to delay the start of incremental marking in that case. 518 if (FLAG_trace_incremental_marking) { 519 PrintF("[IncrementalMarking] Start delayed - serializer\n"); 520 } 521 return; 522 } 523 if (FLAG_trace_incremental_marking) { 524 PrintF("[IncrementalMarking] Start marking\n"); 525 } 526 527 is_compacting_ = !FLAG_never_compact && 528 heap_->mark_compact_collector()->StartCompaction( 529 MarkCompactCollector::INCREMENTAL_COMPACTION); 530 531 state_ = MARKING; 532 533 if (heap_->UsingEmbedderHeapTracer()) { 534 heap_->mark_compact_collector()->embedder_heap_tracer()->TracePrologue(); 535 } 536 537 RecordWriteStub::Mode mode = is_compacting_ 538 ? RecordWriteStub::INCREMENTAL_COMPACTION 539 : RecordWriteStub::INCREMENTAL; 540 541 PatchIncrementalMarkingRecordWriteStubs(heap_, mode); 542 543 heap_->mark_compact_collector()->EnsureMarkingDequeIsCommittedAndInitialize( 544 MarkCompactCollector::kMaxMarkingDequeSize); 545 546 ActivateIncrementalWriteBarrier(); 547 548 // Marking bits are cleared by the sweeper. 549 #ifdef VERIFY_HEAP 550 if (FLAG_verify_heap) { 551 heap_->mark_compact_collector()->VerifyMarkbitsAreClean(); 552 } 553 #endif 554 555 heap_->CompletelyClearInstanceofCache(); 556 heap_->isolate()->compilation_cache()->MarkCompactPrologue(); 557 558 // Mark strong roots grey. 559 IncrementalMarkingRootMarkingVisitor visitor(this); 560 heap_->IterateStrongRoots(&visitor, VISIT_ONLY_STRONG); 561 562 // Ready to start incremental marking. 563 if (FLAG_trace_incremental_marking) { 564 PrintF("[IncrementalMarking] Running\n"); 565 } 566 } 567 568 void IncrementalMarking::StartBlackAllocation() { 569 DCHECK(FLAG_black_allocation); 570 DCHECK(IsMarking()); 571 black_allocation_ = true; 572 OldSpace* old_space = heap()->old_space(); 573 old_space->EmptyAllocationInfo(); 574 old_space->free_list()->Reset(); 575 if (FLAG_trace_incremental_marking) { 576 PrintF("[IncrementalMarking] Black allocation started\n"); 577 } 578 } 579 580 void IncrementalMarking::FinishBlackAllocation() { 581 if (black_allocation_) { 582 black_allocation_ = false; 583 if (FLAG_trace_incremental_marking) { 584 PrintF("[IncrementalMarking] Black allocation finished\n"); 585 } 586 } 587 } 588 589 void IncrementalMarking::MarkRoots() { 590 DCHECK(!finalize_marking_completed_); 591 DCHECK(IsMarking()); 592 593 IncrementalMarkingRootMarkingVisitor visitor(this); 594 heap_->IterateStrongRoots(&visitor, VISIT_ONLY_STRONG); 595 } 596 597 598 void IncrementalMarking::MarkObjectGroups() { 599 DCHECK(!heap_->UsingEmbedderHeapTracer()); 600 DCHECK(!finalize_marking_completed_); 601 DCHECK(IsMarking()); 602 603 IncrementalMarkingRootMarkingVisitor visitor(this); 604 heap_->mark_compact_collector()->MarkImplicitRefGroups(&MarkObject); 605 heap_->isolate()->global_handles()->IterateObjectGroups( 606 &visitor, &MarkCompactCollector::IsUnmarkedHeapObjectWithHeap); 607 heap_->isolate()->global_handles()->RemoveImplicitRefGroups(); 608 heap_->isolate()->global_handles()->RemoveObjectGroups(); 609 } 610 611 612 void IncrementalMarking::ProcessWeakCells() { 613 DCHECK(!finalize_marking_completed_); 614 DCHECK(IsMarking()); 615 616 Object* the_hole_value = heap()->the_hole_value(); 617 Object* weak_cell_obj = heap()->encountered_weak_cells(); 618 Object* weak_cell_head = Smi::FromInt(0); 619 WeakCell* prev_weak_cell_obj = NULL; 620 while (weak_cell_obj != Smi::FromInt(0)) { 621 WeakCell* weak_cell = reinterpret_cast<WeakCell*>(weak_cell_obj); 622 // We do not insert cleared weak cells into the list, so the value 623 // cannot be a Smi here. 624 HeapObject* value = HeapObject::cast(weak_cell->value()); 625 // Remove weak cells with live objects from the list, they do not need 626 // clearing. 627 if (MarkCompactCollector::IsMarked(value)) { 628 // Record slot, if value is pointing to an evacuation candidate. 629 Object** slot = HeapObject::RawField(weak_cell, WeakCell::kValueOffset); 630 heap_->mark_compact_collector()->RecordSlot(weak_cell, slot, *slot); 631 // Remove entry somewhere after top. 632 if (prev_weak_cell_obj != NULL) { 633 prev_weak_cell_obj->set_next(weak_cell->next()); 634 } 635 weak_cell_obj = weak_cell->next(); 636 weak_cell->clear_next(the_hole_value); 637 } else { 638 if (weak_cell_head == Smi::FromInt(0)) { 639 weak_cell_head = weak_cell; 640 } 641 prev_weak_cell_obj = weak_cell; 642 weak_cell_obj = weak_cell->next(); 643 } 644 } 645 // Top may have changed. 646 heap()->set_encountered_weak_cells(weak_cell_head); 647 } 648 649 650 bool ShouldRetainMap(Map* map, int age) { 651 if (age == 0) { 652 // The map has aged. Do not retain this map. 653 return false; 654 } 655 Object* constructor = map->GetConstructor(); 656 if (!constructor->IsHeapObject() || 657 Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(constructor)))) { 658 // The constructor is dead, no new objects with this map can 659 // be created. Do not retain this map. 660 return false; 661 } 662 return true; 663 } 664 665 666 void IncrementalMarking::RetainMaps() { 667 // Do not retain dead maps if flag disables it or there is 668 // - memory pressure (reduce_memory_footprint_), 669 // - GC is requested by tests or dev-tools (abort_incremental_marking_). 670 bool map_retaining_is_disabled = heap()->ShouldReduceMemory() || 671 heap()->ShouldAbortIncrementalMarking() || 672 FLAG_retain_maps_for_n_gc == 0; 673 ArrayList* retained_maps = heap()->retained_maps(); 674 int length = retained_maps->Length(); 675 // The number_of_disposed_maps separates maps in the retained_maps 676 // array that were created before and after context disposal. 677 // We do not age and retain disposed maps to avoid memory leaks. 678 int number_of_disposed_maps = heap()->number_of_disposed_maps_; 679 for (int i = 0; i < length; i += 2) { 680 DCHECK(retained_maps->Get(i)->IsWeakCell()); 681 WeakCell* cell = WeakCell::cast(retained_maps->Get(i)); 682 if (cell->cleared()) continue; 683 int age = Smi::cast(retained_maps->Get(i + 1))->value(); 684 int new_age; 685 Map* map = Map::cast(cell->value()); 686 MarkBit map_mark = Marking::MarkBitFrom(map); 687 if (i >= number_of_disposed_maps && !map_retaining_is_disabled && 688 Marking::IsWhite(map_mark)) { 689 if (ShouldRetainMap(map, age)) { 690 MarkObject(heap(), map); 691 } 692 Object* prototype = map->prototype(); 693 if (age > 0 && prototype->IsHeapObject() && 694 Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(prototype)))) { 695 // The prototype is not marked, age the map. 696 new_age = age - 1; 697 } else { 698 // The prototype and the constructor are marked, this map keeps only 699 // transition tree alive, not JSObjects. Do not age the map. 700 new_age = age; 701 } 702 } else { 703 new_age = FLAG_retain_maps_for_n_gc; 704 } 705 // Compact the array and update the age. 706 if (new_age != age) { 707 retained_maps->Set(i + 1, Smi::FromInt(new_age)); 708 } 709 } 710 } 711 712 713 void IncrementalMarking::FinalizeIncrementally() { 714 DCHECK(!finalize_marking_completed_); 715 DCHECK(IsMarking()); 716 717 double start = heap_->MonotonicallyIncreasingTimeInMs(); 718 719 int old_marking_deque_top = 720 heap_->mark_compact_collector()->marking_deque()->top(); 721 722 // After finishing incremental marking, we try to discover all unmarked 723 // objects to reduce the marking load in the final pause. 724 // 1) We scan and mark the roots again to find all changes to the root set. 725 // 2) We mark the object groups. 726 // 3) Age and retain maps embedded in optimized code. 727 // 4) Remove weak cell with live values from the list of weak cells, they 728 // do not need processing during GC. 729 MarkRoots(); 730 if (!heap_->UsingEmbedderHeapTracer()) { 731 MarkObjectGroups(); 732 } 733 if (incremental_marking_finalization_rounds_ == 0) { 734 // Map retaining is needed for perfromance, not correctness, 735 // so we can do it only once at the beginning of the finalization. 736 RetainMaps(); 737 } 738 ProcessWeakCells(); 739 740 int marking_progress = 741 abs(old_marking_deque_top - 742 heap_->mark_compact_collector()->marking_deque()->top()); 743 744 double end = heap_->MonotonicallyIncreasingTimeInMs(); 745 double delta = end - start; 746 heap_->tracer()->AddMarkingTime(delta); 747 heap_->tracer()->AddIncrementalMarkingFinalizationStep(delta); 748 if (FLAG_trace_incremental_marking) { 749 PrintF( 750 "[IncrementalMarking] Finalize incrementally round %d, " 751 "spent %d ms, marking progress %d.\n", 752 static_cast<int>(delta), incremental_marking_finalization_rounds_, 753 marking_progress); 754 } 755 756 ++incremental_marking_finalization_rounds_; 757 if ((incremental_marking_finalization_rounds_ >= 758 FLAG_max_incremental_marking_finalization_rounds) || 759 (marking_progress < 760 FLAG_min_progress_during_incremental_marking_finalization)) { 761 finalize_marking_completed_ = true; 762 } 763 764 if (FLAG_black_allocation && !heap()->ShouldReduceMemory() && 765 !black_allocation_) { 766 // TODO(hpayer): Move to an earlier point as soon as we make faster marking 767 // progress. 768 StartBlackAllocation(); 769 } 770 } 771 772 773 void IncrementalMarking::UpdateMarkingDequeAfterScavenge() { 774 if (!IsMarking()) return; 775 776 MarkingDeque* marking_deque = 777 heap_->mark_compact_collector()->marking_deque(); 778 int current = marking_deque->bottom(); 779 int mask = marking_deque->mask(); 780 int limit = marking_deque->top(); 781 HeapObject** array = marking_deque->array(); 782 int new_top = current; 783 784 Map* filler_map = heap_->one_pointer_filler_map(); 785 786 while (current != limit) { 787 HeapObject* obj = array[current]; 788 DCHECK(obj->IsHeapObject()); 789 current = ((current + 1) & mask); 790 // Only pointers to from space have to be updated. 791 if (heap_->InFromSpace(obj)) { 792 MapWord map_word = obj->map_word(); 793 // There may be objects on the marking deque that do not exist anymore, 794 // e.g. left trimmed objects or objects from the root set (frames). 795 // If these object are dead at scavenging time, their marking deque 796 // entries will not point to forwarding addresses. Hence, we can discard 797 // them. 798 if (map_word.IsForwardingAddress()) { 799 HeapObject* dest = map_word.ToForwardingAddress(); 800 if (Page::FromAddress(dest->address())->IsFlagSet(Page::BLACK_PAGE)) 801 continue; 802 array[new_top] = dest; 803 new_top = ((new_top + 1) & mask); 804 DCHECK(new_top != marking_deque->bottom()); 805 #ifdef DEBUG 806 MarkBit mark_bit = Marking::MarkBitFrom(obj); 807 DCHECK(Marking::IsGrey(mark_bit) || 808 (obj->IsFiller() && Marking::IsWhite(mark_bit))); 809 #endif 810 } 811 } else if (obj->map() != filler_map) { 812 // Skip one word filler objects that appear on the 813 // stack when we perform in place array shift. 814 array[new_top] = obj; 815 new_top = ((new_top + 1) & mask); 816 DCHECK(new_top != marking_deque->bottom()); 817 #ifdef DEBUG 818 MarkBit mark_bit = Marking::MarkBitFrom(obj); 819 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); 820 DCHECK(Marking::IsGrey(mark_bit) || 821 (obj->IsFiller() && Marking::IsWhite(mark_bit)) || 822 (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR) && 823 Marking::IsBlack(mark_bit))); 824 #endif 825 } 826 } 827 marking_deque->set_top(new_top); 828 } 829 830 831 void IncrementalMarking::VisitObject(Map* map, HeapObject* obj, int size) { 832 MarkObject(heap_, map); 833 834 IncrementalMarkingMarkingVisitor::IterateBody(map, obj); 835 836 MarkBit mark_bit = Marking::MarkBitFrom(obj); 837 #if ENABLE_SLOW_DCHECKS 838 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); 839 SLOW_DCHECK(Marking::IsGrey(mark_bit) || 840 (obj->IsFiller() && Marking::IsWhite(mark_bit)) || 841 (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR) && 842 Marking::IsBlack(mark_bit))); 843 #endif 844 MarkBlackOrKeepBlack(obj, mark_bit, size); 845 } 846 847 848 void IncrementalMarking::MarkObject(Heap* heap, HeapObject* obj) { 849 MarkBit mark_bit = Marking::MarkBitFrom(obj); 850 if (Marking::IsWhite(mark_bit)) { 851 heap->incremental_marking()->WhiteToGreyAndPush(obj, mark_bit); 852 } 853 } 854 855 856 intptr_t IncrementalMarking::ProcessMarkingDeque(intptr_t bytes_to_process) { 857 intptr_t bytes_processed = 0; 858 Map* one_pointer_filler_map = heap_->one_pointer_filler_map(); 859 Map* two_pointer_filler_map = heap_->two_pointer_filler_map(); 860 MarkingDeque* marking_deque = 861 heap_->mark_compact_collector()->marking_deque(); 862 while (!marking_deque->IsEmpty() && bytes_processed < bytes_to_process) { 863 HeapObject* obj = marking_deque->Pop(); 864 865 // Explicitly skip one and two word fillers. Incremental markbit patterns 866 // are correct only for objects that occupy at least two words. 867 // Moreover, slots filtering for left-trimmed arrays works only when 868 // the distance between the old array start and the new array start 869 // is greater than two if both starts are marked. 870 Map* map = obj->map(); 871 if (map == one_pointer_filler_map || map == two_pointer_filler_map) 872 continue; 873 874 int size = obj->SizeFromMap(map); 875 unscanned_bytes_of_large_object_ = 0; 876 VisitObject(map, obj, size); 877 bytes_processed += size - unscanned_bytes_of_large_object_; 878 } 879 return bytes_processed; 880 } 881 882 883 void IncrementalMarking::ProcessMarkingDeque() { 884 Map* filler_map = heap_->one_pointer_filler_map(); 885 MarkingDeque* marking_deque = 886 heap_->mark_compact_collector()->marking_deque(); 887 while (!marking_deque->IsEmpty()) { 888 HeapObject* obj = marking_deque->Pop(); 889 890 // Explicitly skip one word fillers. Incremental markbit patterns are 891 // correct only for objects that occupy at least two words. 892 Map* map = obj->map(); 893 if (map == filler_map) continue; 894 895 VisitObject(map, obj, obj->SizeFromMap(map)); 896 } 897 } 898 899 900 void IncrementalMarking::Hurry() { 901 // A scavenge may have pushed new objects on the marking deque (due to black 902 // allocation) even in COMPLETE state. This may happen if scavenges are 903 // forced e.g. in tests. It should not happen when COMPLETE was set when 904 // incremental marking finished and a regular GC was triggered after that 905 // because should_hurry_ will force a full GC. 906 if (!heap_->mark_compact_collector()->marking_deque()->IsEmpty()) { 907 double start = 0.0; 908 if (FLAG_trace_incremental_marking || FLAG_print_cumulative_gc_stat) { 909 start = heap_->MonotonicallyIncreasingTimeInMs(); 910 if (FLAG_trace_incremental_marking) { 911 PrintF("[IncrementalMarking] Hurry\n"); 912 } 913 } 914 // TODO(gc) hurry can mark objects it encounters black as mutator 915 // was stopped. 916 ProcessMarkingDeque(); 917 state_ = COMPLETE; 918 if (FLAG_trace_incremental_marking || FLAG_print_cumulative_gc_stat) { 919 double end = heap_->MonotonicallyIncreasingTimeInMs(); 920 double delta = end - start; 921 heap_->tracer()->AddMarkingTime(delta); 922 if (FLAG_trace_incremental_marking) { 923 PrintF("[IncrementalMarking] Complete (hurry), spent %d ms.\n", 924 static_cast<int>(delta)); 925 } 926 } 927 } 928 929 Object* context = heap_->native_contexts_list(); 930 while (!context->IsUndefined(heap_->isolate())) { 931 // GC can happen when the context is not fully initialized, 932 // so the cache can be undefined. 933 HeapObject* cache = HeapObject::cast( 934 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX)); 935 if (!cache->IsUndefined(heap_->isolate())) { 936 MarkBit mark_bit = Marking::MarkBitFrom(cache); 937 if (Marking::IsGrey(mark_bit)) { 938 Marking::GreyToBlack(mark_bit); 939 MemoryChunk::IncrementLiveBytesFromGC(cache, cache->Size()); 940 } 941 } 942 context = Context::cast(context)->next_context_link(); 943 } 944 } 945 946 947 void IncrementalMarking::Stop() { 948 if (IsStopped()) return; 949 if (FLAG_trace_incremental_marking) { 950 PrintF("[IncrementalMarking] Stopping.\n"); 951 } 952 953 heap_->new_space()->RemoveAllocationObserver(&observer_); 954 IncrementalMarking::set_should_hurry(false); 955 ResetStepCounters(); 956 if (IsMarking()) { 957 PatchIncrementalMarkingRecordWriteStubs(heap_, 958 RecordWriteStub::STORE_BUFFER_ONLY); 959 DeactivateIncrementalWriteBarrier(); 960 } 961 heap_->isolate()->stack_guard()->ClearGC(); 962 state_ = STOPPED; 963 is_compacting_ = false; 964 FinishBlackAllocation(); 965 } 966 967 968 void IncrementalMarking::Finalize() { 969 Hurry(); 970 Stop(); 971 } 972 973 974 void IncrementalMarking::FinalizeMarking(CompletionAction action) { 975 DCHECK(!finalize_marking_completed_); 976 if (FLAG_trace_incremental_marking) { 977 PrintF( 978 "[IncrementalMarking] requesting finalization of incremental " 979 "marking.\n"); 980 } 981 request_type_ = FINALIZATION; 982 if (action == GC_VIA_STACK_GUARD) { 983 heap_->isolate()->stack_guard()->RequestGC(); 984 } 985 } 986 987 988 void IncrementalMarking::MarkingComplete(CompletionAction action) { 989 state_ = COMPLETE; 990 // We will set the stack guard to request a GC now. This will mean the rest 991 // of the GC gets performed as soon as possible (we can't do a GC here in a 992 // record-write context). If a few things get allocated between now and then 993 // that shouldn't make us do a scavenge and keep being incremental, so we set 994 // the should-hurry flag to indicate that there can't be much work left to do. 995 set_should_hurry(true); 996 if (FLAG_trace_incremental_marking) { 997 PrintF("[IncrementalMarking] Complete (normal).\n"); 998 } 999 request_type_ = COMPLETE_MARKING; 1000 if (action == GC_VIA_STACK_GUARD) { 1001 heap_->isolate()->stack_guard()->RequestGC(); 1002 } 1003 } 1004 1005 1006 void IncrementalMarking::Epilogue() { 1007 was_activated_ = false; 1008 finalize_marking_completed_ = false; 1009 incremental_marking_finalization_rounds_ = 0; 1010 } 1011 1012 double IncrementalMarking::AdvanceIncrementalMarking( 1013 double deadline_in_ms, IncrementalMarking::StepActions step_actions) { 1014 DCHECK(!IsStopped()); 1015 1016 intptr_t step_size_in_bytes = GCIdleTimeHandler::EstimateMarkingStepSize( 1017 GCIdleTimeHandler::kIncrementalMarkingStepTimeInMs, 1018 heap() 1019 ->tracer() 1020 ->FinalIncrementalMarkCompactSpeedInBytesPerMillisecond()); 1021 double remaining_time_in_ms = 0.0; 1022 intptr_t bytes_processed = 0; 1023 1024 do { 1025 bytes_processed = 1026 Step(step_size_in_bytes, step_actions.completion_action, 1027 step_actions.force_marking, step_actions.force_completion); 1028 remaining_time_in_ms = 1029 deadline_in_ms - heap()->MonotonicallyIncreasingTimeInMs(); 1030 } while (bytes_processed > 0 && 1031 remaining_time_in_ms >= 1032 2.0 * GCIdleTimeHandler::kIncrementalMarkingStepTimeInMs && 1033 !IsComplete() && 1034 !heap()->mark_compact_collector()->marking_deque()->IsEmpty()); 1035 return remaining_time_in_ms; 1036 } 1037 1038 1039 void IncrementalMarking::OldSpaceStep(intptr_t allocated) { 1040 if (IsStopped() && ShouldActivateEvenWithoutIdleNotification()) { 1041 heap()->StartIncrementalMarking(Heap::kNoGCFlags, kNoGCCallbackFlags, 1042 "old space step"); 1043 } else { 1044 Step(allocated * kFastMarking / kInitialMarkingSpeed, GC_VIA_STACK_GUARD); 1045 } 1046 } 1047 1048 1049 void IncrementalMarking::SpeedUp() { 1050 bool speed_up = false; 1051 1052 if ((steps_count_ % kMarkingSpeedAccellerationInterval) == 0) { 1053 if (FLAG_trace_incremental_marking) { 1054 PrintIsolate(heap()->isolate(), "Speed up marking after %d steps\n", 1055 static_cast<int>(kMarkingSpeedAccellerationInterval)); 1056 } 1057 speed_up = true; 1058 } 1059 1060 bool space_left_is_very_small = 1061 (old_generation_space_available_at_start_of_incremental_ < 10 * MB); 1062 1063 bool only_1_nth_of_space_that_was_available_still_left = 1064 (SpaceLeftInOldSpace() * (marking_speed_ + 1) < 1065 old_generation_space_available_at_start_of_incremental_); 1066 1067 if (space_left_is_very_small || 1068 only_1_nth_of_space_that_was_available_still_left) { 1069 if (FLAG_trace_incremental_marking) 1070 PrintIsolate(heap()->isolate(), 1071 "Speed up marking because of low space left\n"); 1072 speed_up = true; 1073 } 1074 1075 bool size_of_old_space_multiplied_by_n_during_marking = 1076 (heap_->PromotedTotalSize() > 1077 (marking_speed_ + 1) * 1078 old_generation_space_used_at_start_of_incremental_); 1079 if (size_of_old_space_multiplied_by_n_during_marking) { 1080 speed_up = true; 1081 if (FLAG_trace_incremental_marking) { 1082 PrintIsolate(heap()->isolate(), 1083 "Speed up marking because of heap size increase\n"); 1084 } 1085 } 1086 1087 int64_t promoted_during_marking = 1088 heap_->PromotedTotalSize() - 1089 old_generation_space_used_at_start_of_incremental_; 1090 intptr_t delay = marking_speed_ * MB; 1091 intptr_t scavenge_slack = heap_->MaxSemiSpaceSize(); 1092 1093 // We try to scan at at least twice the speed that we are allocating. 1094 if (promoted_during_marking > bytes_scanned_ / 2 + scavenge_slack + delay) { 1095 if (FLAG_trace_incremental_marking) { 1096 PrintIsolate(heap()->isolate(), 1097 "Speed up marking because marker was not keeping up\n"); 1098 } 1099 speed_up = true; 1100 } 1101 1102 if (speed_up) { 1103 if (state_ != MARKING) { 1104 if (FLAG_trace_incremental_marking) { 1105 PrintIsolate(heap()->isolate(), 1106 "Postponing speeding up marking until marking starts\n"); 1107 } 1108 } else { 1109 marking_speed_ += kMarkingSpeedAccelleration; 1110 marking_speed_ = static_cast<int>( 1111 Min(kMaxMarkingSpeed, static_cast<intptr_t>(marking_speed_ * 1.3))); 1112 if (FLAG_trace_incremental_marking) { 1113 PrintIsolate(heap()->isolate(), "Marking speed increased to %d\n", 1114 marking_speed_); 1115 } 1116 } 1117 } 1118 } 1119 1120 void IncrementalMarking::FinalizeSweeping() { 1121 DCHECK(state_ == SWEEPING); 1122 if (heap_->mark_compact_collector()->sweeping_in_progress() && 1123 (heap_->mark_compact_collector()->sweeper().IsSweepingCompleted() || 1124 !FLAG_concurrent_sweeping)) { 1125 heap_->mark_compact_collector()->EnsureSweepingCompleted(); 1126 } 1127 if (!heap_->mark_compact_collector()->sweeping_in_progress()) { 1128 bytes_scanned_ = 0; 1129 StartMarking(); 1130 } 1131 } 1132 1133 intptr_t IncrementalMarking::Step(intptr_t allocated_bytes, 1134 CompletionAction action, 1135 ForceMarkingAction marking, 1136 ForceCompletionAction completion) { 1137 DCHECK(allocated_bytes >= 0); 1138 1139 if (heap_->gc_state() != Heap::NOT_IN_GC || !FLAG_incremental_marking || 1140 (state_ != SWEEPING && state_ != MARKING)) { 1141 return 0; 1142 } 1143 1144 allocated_ += allocated_bytes; 1145 1146 if (marking == DO_NOT_FORCE_MARKING && allocated_ < kAllocatedThreshold && 1147 write_barriers_invoked_since_last_step_ < 1148 kWriteBarriersInvokedThreshold) { 1149 return 0; 1150 } 1151 1152 // If an idle notification happened recently, we delay marking steps. 1153 if (marking == DO_NOT_FORCE_MARKING && 1154 heap_->RecentIdleNotificationHappened()) { 1155 return 0; 1156 } 1157 1158 intptr_t bytes_processed = 0; 1159 { 1160 HistogramTimerScope incremental_marking_scope( 1161 heap_->isolate()->counters()->gc_incremental_marking()); 1162 TRACE_EVENT0("v8", "V8.GCIncrementalMarking"); 1163 double start = heap_->MonotonicallyIncreasingTimeInMs(); 1164 1165 // The marking speed is driven either by the allocation rate or by the rate 1166 // at which we are having to check the color of objects in the write 1167 // barrier. 1168 // It is possible for a tight non-allocating loop to run a lot of write 1169 // barriers before we get here and check them (marking can only take place 1170 // on 1171 // allocation), so to reduce the lumpiness we don't use the write barriers 1172 // invoked since last step directly to determine the amount of work to do. 1173 intptr_t bytes_to_process = 1174 marking_speed_ * 1175 Max(allocated_, write_barriers_invoked_since_last_step_); 1176 allocated_ = 0; 1177 write_barriers_invoked_since_last_step_ = 0; 1178 1179 bytes_scanned_ += bytes_to_process; 1180 1181 // TODO(hpayer): Do not account for sweeping finalization while marking. 1182 if (state_ == SWEEPING) { 1183 FinalizeSweeping(); 1184 } 1185 1186 if (state_ == MARKING) { 1187 bytes_processed = ProcessMarkingDeque(bytes_to_process); 1188 if (heap_->mark_compact_collector()->marking_deque()->IsEmpty()) { 1189 if (completion == FORCE_COMPLETION || 1190 IsIdleMarkingDelayCounterLimitReached()) { 1191 if (!finalize_marking_completed_) { 1192 FinalizeMarking(action); 1193 } else { 1194 MarkingComplete(action); 1195 } 1196 } else { 1197 IncrementIdleMarkingDelayCounter(); 1198 } 1199 } 1200 } 1201 1202 steps_count_++; 1203 1204 // Speed up marking if we are marking too slow or if we are almost done 1205 // with marking. 1206 SpeedUp(); 1207 1208 double end = heap_->MonotonicallyIncreasingTimeInMs(); 1209 double duration = (end - start); 1210 // Note that we report zero bytes here when sweeping was in progress or 1211 // when we just started incremental marking. In these cases we did not 1212 // process the marking deque. 1213 heap_->tracer()->AddIncrementalMarkingStep(duration, bytes_processed); 1214 } 1215 return bytes_processed; 1216 } 1217 1218 1219 void IncrementalMarking::ResetStepCounters() { 1220 steps_count_ = 0; 1221 old_generation_space_available_at_start_of_incremental_ = 1222 SpaceLeftInOldSpace(); 1223 old_generation_space_used_at_start_of_incremental_ = 1224 heap_->PromotedTotalSize(); 1225 bytes_rescanned_ = 0; 1226 marking_speed_ = kInitialMarkingSpeed; 1227 bytes_scanned_ = 0; 1228 write_barriers_invoked_since_last_step_ = 0; 1229 } 1230 1231 1232 int64_t IncrementalMarking::SpaceLeftInOldSpace() { 1233 return heap_->MaxOldGenerationSize() - heap_->PromotedSpaceSizeOfObjects(); 1234 } 1235 1236 1237 bool IncrementalMarking::IsIdleMarkingDelayCounterLimitReached() { 1238 return idle_marking_delay_counter_ > kMaxIdleMarkingDelayCounter; 1239 } 1240 1241 1242 void IncrementalMarking::IncrementIdleMarkingDelayCounter() { 1243 idle_marking_delay_counter_++; 1244 } 1245 1246 1247 void IncrementalMarking::ClearIdleMarkingDelayCounter() { 1248 idle_marking_delay_counter_ = 0; 1249 } 1250 } // namespace internal 1251 } // namespace v8 1252