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/heap.h" 6 7 #include <unordered_map> 8 #include <unordered_set> 9 10 #include "src/accessors.h" 11 #include "src/api-inl.h" 12 #include "src/assembler-inl.h" 13 #include "src/ast/context-slot-cache.h" 14 #include "src/base/bits.h" 15 #include "src/base/once.h" 16 #include "src/base/utils/random-number-generator.h" 17 #include "src/bootstrapper.h" 18 #include "src/code-stubs.h" 19 #include "src/compilation-cache.h" 20 #include "src/conversions.h" 21 #include "src/debug/debug.h" 22 #include "src/deoptimizer.h" 23 #include "src/feedback-vector.h" 24 #include "src/global-handles.h" 25 #include "src/heap/array-buffer-collector.h" 26 #include "src/heap/array-buffer-tracker-inl.h" 27 #include "src/heap/barrier.h" 28 #include "src/heap/code-stats.h" 29 #include "src/heap/concurrent-marking.h" 30 #include "src/heap/embedder-tracing.h" 31 #include "src/heap/gc-idle-time-handler.h" 32 #include "src/heap/gc-tracer.h" 33 #include "src/heap/heap-controller.h" 34 #include "src/heap/heap-write-barrier-inl.h" 35 #include "src/heap/incremental-marking.h" 36 #include "src/heap/item-parallel-job.h" 37 #include "src/heap/mark-compact-inl.h" 38 #include "src/heap/mark-compact.h" 39 #include "src/heap/memory-reducer.h" 40 #include "src/heap/object-stats.h" 41 #include "src/heap/objects-visiting-inl.h" 42 #include "src/heap/objects-visiting.h" 43 #include "src/heap/remembered-set.h" 44 #include "src/heap/scavenge-job.h" 45 #include "src/heap/scavenger-inl.h" 46 #include "src/heap/store-buffer.h" 47 #include "src/heap/stress-marking-observer.h" 48 #include "src/heap/stress-scavenge-observer.h" 49 #include "src/heap/sweeper.h" 50 #include "src/instruction-stream.h" 51 #include "src/interpreter/interpreter.h" 52 #include "src/objects/data-handler.h" 53 #include "src/objects/hash-table-inl.h" 54 #include "src/objects/maybe-object.h" 55 #include "src/objects/shared-function-info.h" 56 #include "src/regexp/jsregexp.h" 57 #include "src/runtime-profiler.h" 58 #include "src/snapshot/natives.h" 59 #include "src/snapshot/serializer-common.h" 60 #include "src/snapshot/snapshot.h" 61 #include "src/tracing/trace-event.h" 62 #include "src/unicode-decoder.h" 63 #include "src/unicode-inl.h" 64 #include "src/utils-inl.h" 65 #include "src/utils.h" 66 #include "src/v8.h" 67 #include "src/vm-state-inl.h" 68 69 // Has to be the last include (doesn't have include guards): 70 #include "src/objects/object-macros.h" 71 72 namespace v8 { 73 namespace internal { 74 75 void Heap::SetArgumentsAdaptorDeoptPCOffset(int pc_offset) { 76 DCHECK_EQ(Smi::kZero, arguments_adaptor_deopt_pc_offset()); 77 set_arguments_adaptor_deopt_pc_offset(Smi::FromInt(pc_offset)); 78 } 79 80 void Heap::SetConstructStubCreateDeoptPCOffset(int pc_offset) { 81 DCHECK(construct_stub_create_deopt_pc_offset() == Smi::kZero); 82 set_construct_stub_create_deopt_pc_offset(Smi::FromInt(pc_offset)); 83 } 84 85 void Heap::SetConstructStubInvokeDeoptPCOffset(int pc_offset) { 86 DCHECK(construct_stub_invoke_deopt_pc_offset() == Smi::kZero); 87 set_construct_stub_invoke_deopt_pc_offset(Smi::FromInt(pc_offset)); 88 } 89 90 void Heap::SetInterpreterEntryReturnPCOffset(int pc_offset) { 91 DCHECK_EQ(Smi::kZero, interpreter_entry_return_pc_offset()); 92 set_interpreter_entry_return_pc_offset(Smi::FromInt(pc_offset)); 93 } 94 95 void Heap::SetSerializedObjects(FixedArray* objects) { 96 DCHECK(isolate()->serializer_enabled()); 97 set_serialized_objects(objects); 98 } 99 100 void Heap::SetSerializedGlobalProxySizes(FixedArray* sizes) { 101 DCHECK(isolate()->serializer_enabled()); 102 set_serialized_global_proxy_sizes(sizes); 103 } 104 105 bool Heap::GCCallbackTuple::operator==( 106 const Heap::GCCallbackTuple& other) const { 107 return other.callback == callback && other.data == data; 108 } 109 110 Heap::GCCallbackTuple& Heap::GCCallbackTuple::operator=( 111 const Heap::GCCallbackTuple& other) { 112 callback = other.callback; 113 gc_type = other.gc_type; 114 data = other.data; 115 return *this; 116 } 117 118 struct Heap::StrongRootsList { 119 Object** start; 120 Object** end; 121 StrongRootsList* next; 122 }; 123 124 class IdleScavengeObserver : public AllocationObserver { 125 public: 126 IdleScavengeObserver(Heap& heap, intptr_t step_size) 127 : AllocationObserver(step_size), heap_(heap) {} 128 129 void Step(int bytes_allocated, Address, size_t) override { 130 heap_.ScheduleIdleScavengeIfNeeded(bytes_allocated); 131 } 132 133 private: 134 Heap& heap_; 135 }; 136 137 Heap::Heap() 138 : external_memory_(0), 139 external_memory_limit_(kExternalAllocationSoftLimit), 140 external_memory_at_last_mark_compact_(0), 141 external_memory_concurrently_freed_(0), 142 isolate_(nullptr), 143 code_range_size_(0), 144 // semispace_size_ should be a power of 2 and old_generation_size_ should 145 // be a multiple of Page::kPageSize. 146 max_semi_space_size_(8 * (kPointerSize / 4) * MB), 147 initial_semispace_size_(kMinSemiSpaceSizeInKB * KB), 148 max_old_generation_size_(700ul * (kPointerSize / 4) * MB), 149 initial_max_old_generation_size_(max_old_generation_size_), 150 initial_old_generation_size_(max_old_generation_size_ / 151 kInitalOldGenerationLimitFactor), 152 old_generation_size_configured_(false), 153 // Variables set based on semispace_size_ and old_generation_size_ in 154 // ConfigureHeap. 155 // Will be 4 * reserved_semispace_size_ to ensure that young 156 // generation can be aligned to its size. 157 maximum_committed_(0), 158 survived_since_last_expansion_(0), 159 survived_last_scavenge_(0), 160 always_allocate_scope_count_(0), 161 memory_pressure_level_(MemoryPressureLevel::kNone), 162 contexts_disposed_(0), 163 number_of_disposed_maps_(0), 164 new_space_(nullptr), 165 old_space_(nullptr), 166 code_space_(nullptr), 167 map_space_(nullptr), 168 lo_space_(nullptr), 169 new_lo_space_(nullptr), 170 read_only_space_(nullptr), 171 write_protect_code_memory_(false), 172 code_space_memory_modification_scope_depth_(0), 173 gc_state_(NOT_IN_GC), 174 gc_post_processing_depth_(0), 175 allocations_count_(0), 176 raw_allocations_hash_(0), 177 stress_marking_observer_(nullptr), 178 stress_scavenge_observer_(nullptr), 179 allocation_step_in_progress_(false), 180 max_marking_limit_reached_(0.0), 181 ms_count_(0), 182 gc_count_(0), 183 consecutive_ineffective_mark_compacts_(0), 184 mmap_region_base_(0), 185 remembered_unmapped_pages_index_(0), 186 old_generation_allocation_limit_(initial_old_generation_size_), 187 inline_allocation_disabled_(false), 188 tracer_(nullptr), 189 promoted_objects_size_(0), 190 promotion_ratio_(0), 191 semi_space_copied_object_size_(0), 192 previous_semi_space_copied_object_size_(0), 193 semi_space_copied_rate_(0), 194 nodes_died_in_new_space_(0), 195 nodes_copied_in_new_space_(0), 196 nodes_promoted_(0), 197 maximum_size_scavenges_(0), 198 last_idle_notification_time_(0.0), 199 last_gc_time_(0.0), 200 mark_compact_collector_(nullptr), 201 minor_mark_compact_collector_(nullptr), 202 array_buffer_collector_(nullptr), 203 memory_allocator_(nullptr), 204 store_buffer_(nullptr), 205 incremental_marking_(nullptr), 206 concurrent_marking_(nullptr), 207 gc_idle_time_handler_(nullptr), 208 memory_reducer_(nullptr), 209 live_object_stats_(nullptr), 210 dead_object_stats_(nullptr), 211 scavenge_job_(nullptr), 212 parallel_scavenge_semaphore_(0), 213 idle_scavenge_observer_(nullptr), 214 new_space_allocation_counter_(0), 215 old_generation_allocation_counter_at_last_gc_(0), 216 old_generation_size_at_last_gc_(0), 217 global_pretenuring_feedback_(kInitialFeedbackCapacity), 218 is_marking_flag_(false), 219 ring_buffer_full_(false), 220 ring_buffer_end_(0), 221 configured_(false), 222 current_gc_flags_(Heap::kNoGCFlags), 223 current_gc_callback_flags_(GCCallbackFlags::kNoGCCallbackFlags), 224 external_string_table_(this), 225 gc_callbacks_depth_(0), 226 deserialization_complete_(false), 227 strong_roots_list_(nullptr), 228 heap_iterator_depth_(0), 229 local_embedder_heap_tracer_(nullptr), 230 fast_promotion_mode_(false), 231 force_oom_(false), 232 delay_sweeper_tasks_for_testing_(false), 233 pending_layout_change_object_(nullptr), 234 unprotected_memory_chunks_registry_enabled_(false) 235 #ifdef V8_ENABLE_ALLOCATION_TIMEOUT 236 , 237 allocation_timeout_(0) 238 #endif // V8_ENABLE_ALLOCATION_TIMEOUT 239 { 240 // Ensure old_generation_size_ is a multiple of kPageSize. 241 DCHECK_EQ(0, max_old_generation_size_ & (Page::kPageSize - 1)); 242 243 memset(roots_, 0, sizeof(roots_[0]) * kRootListLength); 244 set_native_contexts_list(nullptr); 245 set_allocation_sites_list(Smi::kZero); 246 // Put a dummy entry in the remembered pages so we can find the list the 247 // minidump even if there are no real unmapped pages. 248 RememberUnmappedPage(kNullAddress, false); 249 } 250 251 size_t Heap::MaxReserved() { 252 const double kFactor = Page::kPageSize * 1.0 / Page::kAllocatableMemory; 253 return static_cast<size_t>( 254 (2 * max_semi_space_size_ + max_old_generation_size_) * kFactor); 255 } 256 257 size_t Heap::ComputeMaxOldGenerationSize(uint64_t physical_memory) { 258 const size_t old_space_physical_memory_factor = 4; 259 size_t computed_size = static_cast<size_t>(physical_memory / i::MB / 260 old_space_physical_memory_factor * 261 kPointerMultiplier); 262 return Max(Min(computed_size, HeapController::kMaxHeapSize), 263 HeapController::kMinHeapSize); 264 } 265 266 size_t Heap::Capacity() { 267 if (!HasBeenSetUp()) return 0; 268 269 return new_space_->Capacity() + OldGenerationCapacity(); 270 } 271 272 size_t Heap::OldGenerationCapacity() { 273 if (!HasBeenSetUp()) return 0; 274 PagedSpaces spaces(this, PagedSpaces::SpacesSpecifier::kAllPagedSpaces); 275 size_t total = 0; 276 for (PagedSpace* space = spaces.next(); space != nullptr; 277 space = spaces.next()) { 278 total += space->Capacity(); 279 } 280 return total + lo_space_->SizeOfObjects(); 281 } 282 283 size_t Heap::CommittedOldGenerationMemory() { 284 if (!HasBeenSetUp()) return 0; 285 286 PagedSpaces spaces(this, PagedSpaces::SpacesSpecifier::kAllPagedSpaces); 287 size_t total = 0; 288 for (PagedSpace* space = spaces.next(); space != nullptr; 289 space = spaces.next()) { 290 total += space->CommittedMemory(); 291 } 292 return total + lo_space_->Size(); 293 } 294 295 size_t Heap::CommittedMemoryOfHeapAndUnmapper() { 296 if (!HasBeenSetUp()) return 0; 297 298 return CommittedMemory() + 299 memory_allocator()->unmapper()->CommittedBufferedMemory(); 300 } 301 302 size_t Heap::CommittedMemory() { 303 if (!HasBeenSetUp()) return 0; 304 305 return new_space_->CommittedMemory() + CommittedOldGenerationMemory(); 306 } 307 308 309 size_t Heap::CommittedPhysicalMemory() { 310 if (!HasBeenSetUp()) return 0; 311 312 size_t total = 0; 313 for (SpaceIterator it(this); it.has_next();) { 314 total += it.next()->CommittedPhysicalMemory(); 315 } 316 317 return total; 318 } 319 320 size_t Heap::CommittedMemoryExecutable() { 321 if (!HasBeenSetUp()) return 0; 322 323 return static_cast<size_t>(memory_allocator()->SizeExecutable()); 324 } 325 326 327 void Heap::UpdateMaximumCommitted() { 328 if (!HasBeenSetUp()) return; 329 330 const size_t current_committed_memory = CommittedMemory(); 331 if (current_committed_memory > maximum_committed_) { 332 maximum_committed_ = current_committed_memory; 333 } 334 } 335 336 size_t Heap::Available() { 337 if (!HasBeenSetUp()) return 0; 338 339 size_t total = 0; 340 341 for (SpaceIterator it(this); it.has_next();) { 342 total += it.next()->Available(); 343 } 344 return total; 345 } 346 347 bool Heap::CanExpandOldGeneration(size_t size) { 348 if (force_oom_) return false; 349 if (OldGenerationCapacity() + size > MaxOldGenerationSize()) return false; 350 // The OldGenerationCapacity does not account compaction spaces used 351 // during evacuation. Ensure that expanding the old generation does push 352 // the total allocated memory size over the maximum heap size. 353 return memory_allocator()->Size() + size <= MaxReserved(); 354 } 355 356 bool Heap::HasBeenSetUp() { 357 // We will always have a new space when the heap is set up. 358 return new_space_ != nullptr; 359 } 360 361 362 GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space, 363 const char** reason) { 364 // Is global GC requested? 365 if (space != NEW_SPACE) { 366 isolate_->counters()->gc_compactor_caused_by_request()->Increment(); 367 *reason = "GC in old space requested"; 368 return MARK_COMPACTOR; 369 } 370 371 if (FLAG_gc_global || (FLAG_stress_compaction && (gc_count_ & 1) != 0)) { 372 *reason = "GC in old space forced by flags"; 373 return MARK_COMPACTOR; 374 } 375 376 if (incremental_marking()->NeedsFinalization() && 377 AllocationLimitOvershotByLargeMargin()) { 378 *reason = "Incremental marking needs finalization"; 379 return MARK_COMPACTOR; 380 } 381 382 // Over-estimate the new space size using capacity to allow some slack. 383 if (!CanExpandOldGeneration(new_space_->TotalCapacity())) { 384 isolate_->counters() 385 ->gc_compactor_caused_by_oldspace_exhaustion() 386 ->Increment(); 387 *reason = "scavenge might not succeed"; 388 return MARK_COMPACTOR; 389 } 390 391 // Default 392 *reason = nullptr; 393 return YoungGenerationCollector(); 394 } 395 396 void Heap::SetGCState(HeapState state) { 397 gc_state_ = state; 398 } 399 400 void Heap::PrintShortHeapStatistics() { 401 if (!FLAG_trace_gc_verbose) return; 402 PrintIsolate(isolate_, 403 "Memory allocator, used: %6" PRIuS 404 " KB," 405 " available: %6" PRIuS " KB\n", 406 memory_allocator()->Size() / KB, 407 memory_allocator()->Available() / KB); 408 PrintIsolate(isolate_, 409 "Read-only space, used: %6" PRIuS 410 " KB" 411 ", available: %6" PRIuS 412 " KB" 413 ", committed: %6" PRIuS " KB\n", 414 read_only_space_->Size() / KB, 415 read_only_space_->Available() / KB, 416 read_only_space_->CommittedMemory() / KB); 417 PrintIsolate(isolate_, 418 "New space, used: %6" PRIuS 419 " KB" 420 ", available: %6" PRIuS 421 " KB" 422 ", committed: %6" PRIuS " KB\n", 423 new_space_->Size() / KB, new_space_->Available() / KB, 424 new_space_->CommittedMemory() / KB); 425 PrintIsolate(isolate_, 426 "New large object space, used: %6" PRIuS 427 " KB" 428 ", available: %6" PRIuS 429 " KB" 430 ", committed: %6" PRIuS " KB\n", 431 new_lo_space_->SizeOfObjects() / KB, 432 new_lo_space_->Available() / KB, 433 new_lo_space_->CommittedMemory() / KB); 434 PrintIsolate(isolate_, 435 "Old space, used: %6" PRIuS 436 " KB" 437 ", available: %6" PRIuS 438 " KB" 439 ", committed: %6" PRIuS " KB\n", 440 old_space_->SizeOfObjects() / KB, old_space_->Available() / KB, 441 old_space_->CommittedMemory() / KB); 442 PrintIsolate(isolate_, 443 "Code space, used: %6" PRIuS 444 " KB" 445 ", available: %6" PRIuS 446 " KB" 447 ", committed: %6" PRIuS "KB\n", 448 code_space_->SizeOfObjects() / KB, code_space_->Available() / KB, 449 code_space_->CommittedMemory() / KB); 450 PrintIsolate(isolate_, 451 "Map space, used: %6" PRIuS 452 " KB" 453 ", available: %6" PRIuS 454 " KB" 455 ", committed: %6" PRIuS " KB\n", 456 map_space_->SizeOfObjects() / KB, map_space_->Available() / KB, 457 map_space_->CommittedMemory() / KB); 458 PrintIsolate(isolate_, 459 "Large object space, used: %6" PRIuS 460 " KB" 461 ", available: %6" PRIuS 462 " KB" 463 ", committed: %6" PRIuS " KB\n", 464 lo_space_->SizeOfObjects() / KB, lo_space_->Available() / KB, 465 lo_space_->CommittedMemory() / KB); 466 PrintIsolate(isolate_, 467 "All spaces, used: %6" PRIuS 468 " KB" 469 ", available: %6" PRIuS 470 " KB" 471 ", committed: %6" PRIuS "KB\n", 472 this->SizeOfObjects() / KB, this->Available() / KB, 473 this->CommittedMemory() / KB); 474 PrintIsolate(isolate_, 475 "Unmapper buffering %d chunks of committed: %6" PRIuS " KB\n", 476 memory_allocator()->unmapper()->NumberOfChunks(), 477 CommittedMemoryOfHeapAndUnmapper() / KB); 478 PrintIsolate(isolate_, "External memory reported: %6" PRId64 " KB\n", 479 external_memory_ / KB); 480 PrintIsolate(isolate_, "External memory global %zu KB\n", 481 external_memory_callback_() / KB); 482 PrintIsolate(isolate_, "Total time spent in GC : %.1f ms\n", 483 total_gc_time_ms_); 484 } 485 486 void Heap::ReportStatisticsAfterGC() { 487 for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount); 488 ++i) { 489 int count = deferred_counters_[i]; 490 deferred_counters_[i] = 0; 491 while (count > 0) { 492 count--; 493 isolate()->CountUsage(static_cast<v8::Isolate::UseCounterFeature>(i)); 494 } 495 } 496 } 497 498 void Heap::AddHeapObjectAllocationTracker( 499 HeapObjectAllocationTracker* tracker) { 500 if (allocation_trackers_.empty()) DisableInlineAllocation(); 501 allocation_trackers_.push_back(tracker); 502 } 503 504 void Heap::RemoveHeapObjectAllocationTracker( 505 HeapObjectAllocationTracker* tracker) { 506 allocation_trackers_.erase(std::remove(allocation_trackers_.begin(), 507 allocation_trackers_.end(), tracker), 508 allocation_trackers_.end()); 509 if (allocation_trackers_.empty()) EnableInlineAllocation(); 510 } 511 512 void Heap::AddRetainingPathTarget(Handle<HeapObject> object, 513 RetainingPathOption option) { 514 if (!FLAG_track_retaining_path) { 515 PrintF("Retaining path tracking requires --track-retaining-path\n"); 516 } else { 517 Handle<WeakArrayList> array(retaining_path_targets(), isolate()); 518 int index = array->length(); 519 array = WeakArrayList::AddToEnd(isolate(), array, 520 MaybeObjectHandle::Weak(object)); 521 set_retaining_path_targets(*array); 522 DCHECK_EQ(array->length(), index + 1); 523 retaining_path_target_option_[index] = option; 524 } 525 } 526 527 bool Heap::IsRetainingPathTarget(HeapObject* object, 528 RetainingPathOption* option) { 529 WeakArrayList* targets = retaining_path_targets(); 530 int length = targets->length(); 531 MaybeObject* object_to_check = HeapObjectReference::Weak(object); 532 for (int i = 0; i < length; i++) { 533 MaybeObject* target = targets->Get(i); 534 DCHECK(target->IsWeakOrClearedHeapObject()); 535 if (target == object_to_check) { 536 DCHECK(retaining_path_target_option_.count(i)); 537 *option = retaining_path_target_option_[i]; 538 return true; 539 } 540 } 541 return false; 542 } 543 544 void Heap::PrintRetainingPath(HeapObject* target, RetainingPathOption option) { 545 PrintF("\n\n\n"); 546 PrintF("#################################################\n"); 547 PrintF("Retaining path for %p:\n", static_cast<void*>(target)); 548 HeapObject* object = target; 549 std::vector<std::pair<HeapObject*, bool>> retaining_path; 550 Root root = Root::kUnknown; 551 bool ephemeron = false; 552 while (true) { 553 retaining_path.push_back(std::make_pair(object, ephemeron)); 554 if (option == RetainingPathOption::kTrackEphemeronPath && 555 ephemeron_retainer_.count(object)) { 556 object = ephemeron_retainer_[object]; 557 ephemeron = true; 558 } else if (retainer_.count(object)) { 559 object = retainer_[object]; 560 ephemeron = false; 561 } else { 562 if (retaining_root_.count(object)) { 563 root = retaining_root_[object]; 564 } 565 break; 566 } 567 } 568 int distance = static_cast<int>(retaining_path.size()); 569 for (auto node : retaining_path) { 570 HeapObject* object = node.first; 571 bool ephemeron = node.second; 572 PrintF("\n"); 573 PrintF("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"); 574 PrintF("Distance from root %d%s: ", distance, 575 ephemeron ? " (ephemeron)" : ""); 576 object->ShortPrint(); 577 PrintF("\n"); 578 #ifdef OBJECT_PRINT 579 object->Print(); 580 PrintF("\n"); 581 #endif 582 --distance; 583 } 584 PrintF("\n"); 585 PrintF("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"); 586 PrintF("Root: %s\n", RootVisitor::RootName(root)); 587 PrintF("-------------------------------------------------\n"); 588 } 589 590 void Heap::AddRetainer(HeapObject* retainer, HeapObject* object) { 591 if (retainer_.count(object)) return; 592 retainer_[object] = retainer; 593 RetainingPathOption option = RetainingPathOption::kDefault; 594 if (IsRetainingPathTarget(object, &option)) { 595 // Check if the retaining path was already printed in 596 // AddEphemeronRetainer(). 597 if (ephemeron_retainer_.count(object) == 0 || 598 option == RetainingPathOption::kDefault) { 599 PrintRetainingPath(object, option); 600 } 601 } 602 } 603 604 void Heap::AddEphemeronRetainer(HeapObject* retainer, HeapObject* object) { 605 if (ephemeron_retainer_.count(object)) return; 606 ephemeron_retainer_[object] = retainer; 607 RetainingPathOption option = RetainingPathOption::kDefault; 608 if (IsRetainingPathTarget(object, &option) && 609 option == RetainingPathOption::kTrackEphemeronPath) { 610 // Check if the retaining path was already printed in AddRetainer(). 611 if (retainer_.count(object) == 0) { 612 PrintRetainingPath(object, option); 613 } 614 } 615 } 616 617 void Heap::AddRetainingRoot(Root root, HeapObject* object) { 618 if (retaining_root_.count(object)) return; 619 retaining_root_[object] = root; 620 RetainingPathOption option = RetainingPathOption::kDefault; 621 if (IsRetainingPathTarget(object, &option)) { 622 PrintRetainingPath(object, option); 623 } 624 } 625 626 void Heap::IncrementDeferredCount(v8::Isolate::UseCounterFeature feature) { 627 deferred_counters_[feature]++; 628 } 629 630 bool Heap::UncommitFromSpace() { return new_space_->UncommitFromSpace(); } 631 632 void Heap::GarbageCollectionPrologue() { 633 TRACE_GC(tracer(), GCTracer::Scope::HEAP_PROLOGUE); 634 { 635 AllowHeapAllocation for_the_first_part_of_prologue; 636 gc_count_++; 637 638 #ifdef VERIFY_HEAP 639 if (FLAG_verify_heap) { 640 Verify(); 641 } 642 #endif 643 } 644 645 // Reset GC statistics. 646 promoted_objects_size_ = 0; 647 previous_semi_space_copied_object_size_ = semi_space_copied_object_size_; 648 semi_space_copied_object_size_ = 0; 649 nodes_died_in_new_space_ = 0; 650 nodes_copied_in_new_space_ = 0; 651 nodes_promoted_ = 0; 652 653 UpdateMaximumCommitted(); 654 655 #ifdef DEBUG 656 DCHECK(!AllowHeapAllocation::IsAllowed() && gc_state_ == NOT_IN_GC); 657 658 if (FLAG_gc_verbose) Print(); 659 #endif // DEBUG 660 661 if (new_space_->IsAtMaximumCapacity()) { 662 maximum_size_scavenges_++; 663 } else { 664 maximum_size_scavenges_ = 0; 665 } 666 CheckNewSpaceExpansionCriteria(); 667 UpdateNewSpaceAllocationCounter(); 668 if (FLAG_track_retaining_path) { 669 retainer_.clear(); 670 ephemeron_retainer_.clear(); 671 retaining_root_.clear(); 672 } 673 } 674 675 size_t Heap::SizeOfObjects() { 676 size_t total = 0; 677 678 for (SpaceIterator it(this); it.has_next();) { 679 total += it.next()->SizeOfObjects(); 680 } 681 return total; 682 } 683 684 685 const char* Heap::GetSpaceName(int idx) { 686 switch (idx) { 687 case NEW_SPACE: 688 return "new_space"; 689 case OLD_SPACE: 690 return "old_space"; 691 case MAP_SPACE: 692 return "map_space"; 693 case CODE_SPACE: 694 return "code_space"; 695 case LO_SPACE: 696 return "large_object_space"; 697 case NEW_LO_SPACE: 698 return "new_large_object_space"; 699 case RO_SPACE: 700 return "read_only_space"; 701 default: 702 UNREACHABLE(); 703 } 704 return nullptr; 705 } 706 707 void Heap::SetRootCodeStubs(SimpleNumberDictionary* value) { 708 roots_[kCodeStubsRootIndex] = value; 709 } 710 711 void Heap::RepairFreeListsAfterDeserialization() { 712 PagedSpaces spaces(this); 713 for (PagedSpace* space = spaces.next(); space != nullptr; 714 space = spaces.next()) { 715 space->RepairFreeListsAfterDeserialization(); 716 } 717 } 718 719 void Heap::MergeAllocationSitePretenuringFeedback( 720 const PretenuringFeedbackMap& local_pretenuring_feedback) { 721 AllocationSite* site = nullptr; 722 for (auto& site_and_count : local_pretenuring_feedback) { 723 site = site_and_count.first; 724 MapWord map_word = site_and_count.first->map_word(); 725 if (map_word.IsForwardingAddress()) { 726 site = AllocationSite::cast(map_word.ToForwardingAddress()); 727 } 728 729 // We have not validated the allocation site yet, since we have not 730 // dereferenced the site during collecting information. 731 // This is an inlined check of AllocationMemento::IsValid. 732 if (!site->IsAllocationSite() || site->IsZombie()) continue; 733 734 const int value = static_cast<int>(site_and_count.second); 735 DCHECK_LT(0, value); 736 if (site->IncrementMementoFoundCount(value)) { 737 // For sites in the global map the count is accessed through the site. 738 global_pretenuring_feedback_.insert(std::make_pair(site, 0)); 739 } 740 } 741 } 742 743 void Heap::AddAllocationObserversToAllSpaces( 744 AllocationObserver* observer, AllocationObserver* new_space_observer) { 745 DCHECK(observer && new_space_observer); 746 747 for (SpaceIterator it(this); it.has_next();) { 748 Space* space = it.next(); 749 if (space == new_space()) { 750 space->AddAllocationObserver(new_space_observer); 751 } else { 752 space->AddAllocationObserver(observer); 753 } 754 } 755 } 756 757 void Heap::RemoveAllocationObserversFromAllSpaces( 758 AllocationObserver* observer, AllocationObserver* new_space_observer) { 759 DCHECK(observer && new_space_observer); 760 761 for (SpaceIterator it(this); it.has_next();) { 762 Space* space = it.next(); 763 if (space == new_space()) { 764 space->RemoveAllocationObserver(new_space_observer); 765 } else { 766 space->RemoveAllocationObserver(observer); 767 } 768 } 769 } 770 771 class Heap::SkipStoreBufferScope { 772 public: 773 explicit SkipStoreBufferScope(StoreBuffer* store_buffer) 774 : store_buffer_(store_buffer) { 775 store_buffer_->MoveAllEntriesToRememberedSet(); 776 store_buffer_->SetMode(StoreBuffer::IN_GC); 777 } 778 779 ~SkipStoreBufferScope() { 780 DCHECK(store_buffer_->Empty()); 781 store_buffer_->SetMode(StoreBuffer::NOT_IN_GC); 782 } 783 784 private: 785 StoreBuffer* store_buffer_; 786 }; 787 788 namespace { 789 inline bool MakePretenureDecision( 790 AllocationSite* site, AllocationSite::PretenureDecision current_decision, 791 double ratio, bool maximum_size_scavenge) { 792 // Here we just allow state transitions from undecided or maybe tenure 793 // to don't tenure, maybe tenure, or tenure. 794 if ((current_decision == AllocationSite::kUndecided || 795 current_decision == AllocationSite::kMaybeTenure)) { 796 if (ratio >= AllocationSite::kPretenureRatio) { 797 // We just transition into tenure state when the semi-space was at 798 // maximum capacity. 799 if (maximum_size_scavenge) { 800 site->set_deopt_dependent_code(true); 801 site->set_pretenure_decision(AllocationSite::kTenure); 802 // Currently we just need to deopt when we make a state transition to 803 // tenure. 804 return true; 805 } 806 site->set_pretenure_decision(AllocationSite::kMaybeTenure); 807 } else { 808 site->set_pretenure_decision(AllocationSite::kDontTenure); 809 } 810 } 811 return false; 812 } 813 814 inline bool DigestPretenuringFeedback(Isolate* isolate, AllocationSite* site, 815 bool maximum_size_scavenge) { 816 bool deopt = false; 817 int create_count = site->memento_create_count(); 818 int found_count = site->memento_found_count(); 819 bool minimum_mementos_created = 820 create_count >= AllocationSite::kPretenureMinimumCreated; 821 double ratio = minimum_mementos_created || FLAG_trace_pretenuring_statistics 822 ? static_cast<double>(found_count) / create_count 823 : 0.0; 824 AllocationSite::PretenureDecision current_decision = 825 site->pretenure_decision(); 826 827 if (minimum_mementos_created) { 828 deopt = MakePretenureDecision(site, current_decision, ratio, 829 maximum_size_scavenge); 830 } 831 832 if (FLAG_trace_pretenuring_statistics) { 833 PrintIsolate(isolate, 834 "pretenuring: AllocationSite(%p): (created, found, ratio) " 835 "(%d, %d, %f) %s => %s\n", 836 static_cast<void*>(site), create_count, found_count, ratio, 837 site->PretenureDecisionName(current_decision), 838 site->PretenureDecisionName(site->pretenure_decision())); 839 } 840 841 // Clear feedback calculation fields until the next gc. 842 site->set_memento_found_count(0); 843 site->set_memento_create_count(0); 844 return deopt; 845 } 846 } // namespace 847 848 void Heap::RemoveAllocationSitePretenuringFeedback(AllocationSite* site) { 849 global_pretenuring_feedback_.erase(site); 850 } 851 852 bool Heap::DeoptMaybeTenuredAllocationSites() { 853 return new_space_->IsAtMaximumCapacity() && maximum_size_scavenges_ == 0; 854 } 855 856 void Heap::ProcessPretenuringFeedback() { 857 bool trigger_deoptimization = false; 858 if (FLAG_allocation_site_pretenuring) { 859 int tenure_decisions = 0; 860 int dont_tenure_decisions = 0; 861 int allocation_mementos_found = 0; 862 int allocation_sites = 0; 863 int active_allocation_sites = 0; 864 865 AllocationSite* site = nullptr; 866 867 // Step 1: Digest feedback for recorded allocation sites. 868 bool maximum_size_scavenge = MaximumSizeScavenge(); 869 for (auto& site_and_count : global_pretenuring_feedback_) { 870 allocation_sites++; 871 site = site_and_count.first; 872 // Count is always access through the site. 873 DCHECK_EQ(0, site_and_count.second); 874 int found_count = site->memento_found_count(); 875 // An entry in the storage does not imply that the count is > 0 because 876 // allocation sites might have been reset due to too many objects dying 877 // in old space. 878 if (found_count > 0) { 879 DCHECK(site->IsAllocationSite()); 880 active_allocation_sites++; 881 allocation_mementos_found += found_count; 882 if (DigestPretenuringFeedback(isolate_, site, maximum_size_scavenge)) { 883 trigger_deoptimization = true; 884 } 885 if (site->GetPretenureMode() == TENURED) { 886 tenure_decisions++; 887 } else { 888 dont_tenure_decisions++; 889 } 890 } 891 } 892 893 // Step 2: Deopt maybe tenured allocation sites if necessary. 894 bool deopt_maybe_tenured = DeoptMaybeTenuredAllocationSites(); 895 if (deopt_maybe_tenured) { 896 ForeachAllocationSite( 897 allocation_sites_list(), 898 [&allocation_sites, &trigger_deoptimization](AllocationSite* site) { 899 DCHECK(site->IsAllocationSite()); 900 allocation_sites++; 901 if (site->IsMaybeTenure()) { 902 site->set_deopt_dependent_code(true); 903 trigger_deoptimization = true; 904 } 905 }); 906 } 907 908 if (trigger_deoptimization) { 909 isolate_->stack_guard()->RequestDeoptMarkedAllocationSites(); 910 } 911 912 if (FLAG_trace_pretenuring_statistics && 913 (allocation_mementos_found > 0 || tenure_decisions > 0 || 914 dont_tenure_decisions > 0)) { 915 PrintIsolate(isolate(), 916 "pretenuring: deopt_maybe_tenured=%d visited_sites=%d " 917 "active_sites=%d " 918 "mementos=%d tenured=%d not_tenured=%d\n", 919 deopt_maybe_tenured ? 1 : 0, allocation_sites, 920 active_allocation_sites, allocation_mementos_found, 921 tenure_decisions, dont_tenure_decisions); 922 } 923 924 global_pretenuring_feedback_.clear(); 925 global_pretenuring_feedback_.reserve(kInitialFeedbackCapacity); 926 } 927 } 928 929 void Heap::InvalidateCodeEmbeddedObjects(Code* code) { 930 MemoryChunk* chunk = MemoryChunk::FromAddress(code->address()); 931 CodePageMemoryModificationScope modification_scope(chunk); 932 code->InvalidateEmbeddedObjects(this); 933 } 934 935 void Heap::InvalidateCodeDeoptimizationData(Code* code) { 936 MemoryChunk* chunk = MemoryChunk::FromAddress(code->address()); 937 CodePageMemoryModificationScope modification_scope(chunk); 938 code->set_deoptimization_data(ReadOnlyRoots(this).empty_fixed_array()); 939 } 940 941 void Heap::DeoptMarkedAllocationSites() { 942 // TODO(hpayer): If iterating over the allocation sites list becomes a 943 // performance issue, use a cache data structure in heap instead. 944 945 ForeachAllocationSite(allocation_sites_list(), [this](AllocationSite* site) { 946 if (site->deopt_dependent_code()) { 947 site->dependent_code()->MarkCodeForDeoptimization( 948 isolate_, DependentCode::kAllocationSiteTenuringChangedGroup); 949 site->set_deopt_dependent_code(false); 950 } 951 }); 952 953 Deoptimizer::DeoptimizeMarkedCode(isolate_); 954 } 955 956 957 void Heap::GarbageCollectionEpilogue() { 958 TRACE_GC(tracer(), GCTracer::Scope::HEAP_EPILOGUE); 959 if (Heap::ShouldZapGarbage() || FLAG_clear_free_memory) { 960 ZapFromSpace(); 961 } 962 963 #ifdef VERIFY_HEAP 964 if (FLAG_verify_heap) { 965 Verify(); 966 } 967 #endif 968 969 AllowHeapAllocation for_the_rest_of_the_epilogue; 970 971 #ifdef DEBUG 972 if (FLAG_print_global_handles) isolate_->global_handles()->Print(); 973 if (FLAG_print_handles) PrintHandles(); 974 if (FLAG_gc_verbose) Print(); 975 if (FLAG_code_stats) ReportCodeStatistics("After GC"); 976 if (FLAG_check_handle_count) CheckHandleCount(); 977 #endif 978 979 UpdateMaximumCommitted(); 980 981 isolate_->counters()->alive_after_last_gc()->Set( 982 static_cast<int>(SizeOfObjects())); 983 984 isolate_->counters()->string_table_capacity()->Set( 985 string_table()->Capacity()); 986 isolate_->counters()->number_of_symbols()->Set( 987 string_table()->NumberOfElements()); 988 989 if (CommittedMemory() > 0) { 990 isolate_->counters()->external_fragmentation_total()->AddSample( 991 static_cast<int>(100 - (SizeOfObjects() * 100.0) / CommittedMemory())); 992 993 isolate_->counters()->heap_sample_total_committed()->AddSample( 994 static_cast<int>(CommittedMemory() / KB)); 995 isolate_->counters()->heap_sample_total_used()->AddSample( 996 static_cast<int>(SizeOfObjects() / KB)); 997 isolate_->counters()->heap_sample_map_space_committed()->AddSample( 998 static_cast<int>(map_space()->CommittedMemory() / KB)); 999 isolate_->counters()->heap_sample_code_space_committed()->AddSample( 1000 static_cast<int>(code_space()->CommittedMemory() / KB)); 1001 1002 isolate_->counters()->heap_sample_maximum_committed()->AddSample( 1003 static_cast<int>(MaximumCommittedMemory() / KB)); 1004 } 1005 1006 #define UPDATE_COUNTERS_FOR_SPACE(space) \ 1007 isolate_->counters()->space##_bytes_available()->Set( \ 1008 static_cast<int>(space()->Available())); \ 1009 isolate_->counters()->space##_bytes_committed()->Set( \ 1010 static_cast<int>(space()->CommittedMemory())); \ 1011 isolate_->counters()->space##_bytes_used()->Set( \ 1012 static_cast<int>(space()->SizeOfObjects())); 1013 #define UPDATE_FRAGMENTATION_FOR_SPACE(space) \ 1014 if (space()->CommittedMemory() > 0) { \ 1015 isolate_->counters()->external_fragmentation_##space()->AddSample( \ 1016 static_cast<int>(100 - \ 1017 (space()->SizeOfObjects() * 100.0) / \ 1018 space()->CommittedMemory())); \ 1019 } 1020 #define UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(space) \ 1021 UPDATE_COUNTERS_FOR_SPACE(space) \ 1022 UPDATE_FRAGMENTATION_FOR_SPACE(space) 1023 1024 UPDATE_COUNTERS_FOR_SPACE(new_space) 1025 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_space) 1026 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(code_space) 1027 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(map_space) 1028 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(lo_space) 1029 #undef UPDATE_COUNTERS_FOR_SPACE 1030 #undef UPDATE_FRAGMENTATION_FOR_SPACE 1031 #undef UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE 1032 1033 #ifdef DEBUG 1034 ReportStatisticsAfterGC(); 1035 #endif // DEBUG 1036 1037 last_gc_time_ = MonotonicallyIncreasingTimeInMs(); 1038 1039 { 1040 TRACE_GC(tracer(), GCTracer::Scope::HEAP_EPILOGUE_REDUCE_NEW_SPACE); 1041 ReduceNewSpaceSize(); 1042 } 1043 } 1044 1045 class GCCallbacksScope { 1046 public: 1047 explicit GCCallbacksScope(Heap* heap) : heap_(heap) { 1048 heap_->gc_callbacks_depth_++; 1049 } 1050 ~GCCallbacksScope() { heap_->gc_callbacks_depth_--; } 1051 1052 bool CheckReenter() { return heap_->gc_callbacks_depth_ == 1; } 1053 1054 private: 1055 Heap* heap_; 1056 }; 1057 1058 1059 void Heap::HandleGCRequest() { 1060 if (FLAG_stress_scavenge > 0 && stress_scavenge_observer_->HasRequestedGC()) { 1061 CollectAllGarbage(NEW_SPACE, GarbageCollectionReason::kTesting); 1062 stress_scavenge_observer_->RequestedGCDone(); 1063 } else if (HighMemoryPressure()) { 1064 incremental_marking()->reset_request_type(); 1065 CheckMemoryPressure(); 1066 } else if (incremental_marking()->request_type() == 1067 IncrementalMarking::COMPLETE_MARKING) { 1068 incremental_marking()->reset_request_type(); 1069 CollectAllGarbage(current_gc_flags_, 1070 GarbageCollectionReason::kFinalizeMarkingViaStackGuard, 1071 current_gc_callback_flags_); 1072 } else if (incremental_marking()->request_type() == 1073 IncrementalMarking::FINALIZATION && 1074 incremental_marking()->IsMarking() && 1075 !incremental_marking()->finalize_marking_completed()) { 1076 incremental_marking()->reset_request_type(); 1077 FinalizeIncrementalMarkingIncrementally( 1078 GarbageCollectionReason::kFinalizeMarkingViaStackGuard); 1079 } 1080 } 1081 1082 1083 void Heap::ScheduleIdleScavengeIfNeeded(int bytes_allocated) { 1084 scavenge_job_->ScheduleIdleTaskIfNeeded(this, bytes_allocated); 1085 } 1086 1087 HistogramTimer* Heap::GCTypePriorityTimer(GarbageCollector collector) { 1088 if (IsYoungGenerationCollector(collector)) { 1089 if (isolate_->IsIsolateInBackground()) { 1090 return isolate_->counters()->gc_scavenger_background(); 1091 } 1092 return isolate_->counters()->gc_scavenger_foreground(); 1093 } else { 1094 if (!incremental_marking()->IsStopped()) { 1095 if (ShouldReduceMemory()) { 1096 if (isolate_->IsIsolateInBackground()) { 1097 return isolate_->counters()->gc_finalize_reduce_memory_background(); 1098 } 1099 return isolate_->counters()->gc_finalize_reduce_memory_foreground(); 1100 } else { 1101 if (isolate_->IsIsolateInBackground()) { 1102 return isolate_->counters()->gc_finalize_background(); 1103 } 1104 return isolate_->counters()->gc_finalize_foreground(); 1105 } 1106 } else { 1107 if (isolate_->IsIsolateInBackground()) { 1108 return isolate_->counters()->gc_compactor_background(); 1109 } 1110 return isolate_->counters()->gc_compactor_foreground(); 1111 } 1112 } 1113 } 1114 1115 HistogramTimer* Heap::GCTypeTimer(GarbageCollector collector) { 1116 if (IsYoungGenerationCollector(collector)) { 1117 return isolate_->counters()->gc_scavenger(); 1118 } else { 1119 if (!incremental_marking()->IsStopped()) { 1120 if (ShouldReduceMemory()) { 1121 return isolate_->counters()->gc_finalize_reduce_memory(); 1122 } else { 1123 return isolate_->counters()->gc_finalize(); 1124 } 1125 } else { 1126 return isolate_->counters()->gc_compactor(); 1127 } 1128 } 1129 } 1130 1131 void Heap::CollectAllGarbage(int flags, GarbageCollectionReason gc_reason, 1132 const v8::GCCallbackFlags gc_callback_flags) { 1133 // Since we are ignoring the return value, the exact choice of space does 1134 // not matter, so long as we do not specify NEW_SPACE, which would not 1135 // cause a full GC. 1136 set_current_gc_flags(flags); 1137 CollectGarbage(OLD_SPACE, gc_reason, gc_callback_flags); 1138 set_current_gc_flags(kNoGCFlags); 1139 } 1140 1141 namespace { 1142 1143 intptr_t CompareWords(int size, HeapObject* a, HeapObject* b) { 1144 int words = size / kPointerSize; 1145 DCHECK_EQ(a->Size(), size); 1146 DCHECK_EQ(b->Size(), size); 1147 intptr_t* slot_a = reinterpret_cast<intptr_t*>(a->address()); 1148 intptr_t* slot_b = reinterpret_cast<intptr_t*>(b->address()); 1149 for (int i = 0; i < words; i++) { 1150 if (*slot_a != *slot_b) { 1151 return *slot_a - *slot_b; 1152 } 1153 slot_a++; 1154 slot_b++; 1155 } 1156 return 0; 1157 } 1158 1159 void ReportDuplicates(int size, std::vector<HeapObject*>& objects) { 1160 if (objects.size() == 0) return; 1161 1162 sort(objects.begin(), objects.end(), [size](HeapObject* a, HeapObject* b) { 1163 intptr_t c = CompareWords(size, a, b); 1164 if (c != 0) return c < 0; 1165 return a < b; 1166 }); 1167 1168 std::vector<std::pair<int, HeapObject*>> duplicates; 1169 HeapObject* current = objects[0]; 1170 int count = 1; 1171 for (size_t i = 1; i < objects.size(); i++) { 1172 if (CompareWords(size, current, objects[i]) == 0) { 1173 count++; 1174 } else { 1175 if (count > 1) { 1176 duplicates.push_back(std::make_pair(count - 1, current)); 1177 } 1178 count = 1; 1179 current = objects[i]; 1180 } 1181 } 1182 if (count > 1) { 1183 duplicates.push_back(std::make_pair(count - 1, current)); 1184 } 1185 1186 int threshold = FLAG_trace_duplicate_threshold_kb * KB; 1187 1188 sort(duplicates.begin(), duplicates.end()); 1189 for (auto it = duplicates.rbegin(); it != duplicates.rend(); ++it) { 1190 int duplicate_bytes = it->first * size; 1191 if (duplicate_bytes < threshold) break; 1192 PrintF("%d duplicates of size %d each (%dKB)\n", it->first, size, 1193 duplicate_bytes / KB); 1194 PrintF("Sample object: "); 1195 it->second->Print(); 1196 PrintF("============================\n"); 1197 } 1198 } 1199 } // anonymous namespace 1200 1201 void Heap::CollectAllAvailableGarbage(GarbageCollectionReason gc_reason) { 1202 // Since we are ignoring the return value, the exact choice of space does 1203 // not matter, so long as we do not specify NEW_SPACE, which would not 1204 // cause a full GC. 1205 // Major GC would invoke weak handle callbacks on weakly reachable 1206 // handles, but won't collect weakly reachable objects until next 1207 // major GC. Therefore if we collect aggressively and weak handle callback 1208 // has been invoked, we rerun major GC to release objects which become 1209 // garbage. 1210 // Note: as weak callbacks can execute arbitrary code, we cannot 1211 // hope that eventually there will be no weak callbacks invocations. 1212 // Therefore stop recollecting after several attempts. 1213 if (gc_reason == GarbageCollectionReason::kLastResort) { 1214 InvokeNearHeapLimitCallback(); 1215 } 1216 RuntimeCallTimerScope runtime_timer( 1217 isolate(), RuntimeCallCounterId::kGC_Custom_AllAvailableGarbage); 1218 1219 // The optimizing compiler may be unnecessarily holding on to memory. 1220 isolate()->AbortConcurrentOptimization(BlockingBehavior::kDontBlock); 1221 isolate()->ClearSerializerData(); 1222 set_current_gc_flags(kMakeHeapIterableMask | kReduceMemoryFootprintMask); 1223 isolate_->compilation_cache()->Clear(); 1224 const int kMaxNumberOfAttempts = 7; 1225 const int kMinNumberOfAttempts = 2; 1226 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { 1227 if (!CollectGarbage(OLD_SPACE, gc_reason, 1228 v8::kGCCallbackFlagCollectAllAvailableGarbage) && 1229 attempt + 1 >= kMinNumberOfAttempts) { 1230 break; 1231 } 1232 } 1233 1234 set_current_gc_flags(kNoGCFlags); 1235 new_space_->Shrink(); 1236 UncommitFromSpace(); 1237 memory_allocator()->unmapper()->EnsureUnmappingCompleted(); 1238 1239 if (FLAG_trace_duplicate_threshold_kb) { 1240 std::map<int, std::vector<HeapObject*>> objects_by_size; 1241 PagedSpaces spaces(this); 1242 for (PagedSpace* space = spaces.next(); space != nullptr; 1243 space = spaces.next()) { 1244 HeapObjectIterator it(space); 1245 for (HeapObject* obj = it.Next(); obj != nullptr; obj = it.Next()) { 1246 objects_by_size[obj->Size()].push_back(obj); 1247 } 1248 } 1249 { 1250 LargeObjectIterator it(lo_space()); 1251 for (HeapObject* obj = it.Next(); obj != nullptr; obj = it.Next()) { 1252 objects_by_size[obj->Size()].push_back(obj); 1253 } 1254 } 1255 for (auto it = objects_by_size.rbegin(); it != objects_by_size.rend(); 1256 ++it) { 1257 ReportDuplicates(it->first, it->second); 1258 } 1259 } 1260 } 1261 1262 void Heap::ReportExternalMemoryPressure() { 1263 const GCCallbackFlags kGCCallbackFlagsForExternalMemory = 1264 static_cast<GCCallbackFlags>( 1265 kGCCallbackFlagSynchronousPhantomCallbackProcessing | 1266 kGCCallbackFlagCollectAllExternalMemory); 1267 if (external_memory_ > 1268 (external_memory_at_last_mark_compact_ + external_memory_hard_limit())) { 1269 CollectAllGarbage( 1270 kReduceMemoryFootprintMask | kFinalizeIncrementalMarkingMask, 1271 GarbageCollectionReason::kExternalMemoryPressure, 1272 static_cast<GCCallbackFlags>(kGCCallbackFlagCollectAllAvailableGarbage | 1273 kGCCallbackFlagsForExternalMemory)); 1274 return; 1275 } 1276 if (incremental_marking()->IsStopped()) { 1277 if (incremental_marking()->CanBeActivated()) { 1278 StartIncrementalMarking(GCFlagsForIncrementalMarking(), 1279 GarbageCollectionReason::kExternalMemoryPressure, 1280 kGCCallbackFlagsForExternalMemory); 1281 } else { 1282 CollectAllGarbage(i::Heap::kNoGCFlags, 1283 GarbageCollectionReason::kExternalMemoryPressure, 1284 kGCCallbackFlagsForExternalMemory); 1285 } 1286 } else { 1287 // Incremental marking is turned on an has already been started. 1288 const double kMinStepSize = 5; 1289 const double kMaxStepSize = 10; 1290 const double ms_step = 1291 Min(kMaxStepSize, 1292 Max(kMinStepSize, static_cast<double>(external_memory_) / 1293 external_memory_limit_ * kMinStepSize)); 1294 const double deadline = MonotonicallyIncreasingTimeInMs() + ms_step; 1295 // Extend the gc callback flags with external memory flags. 1296 current_gc_callback_flags_ = static_cast<GCCallbackFlags>( 1297 current_gc_callback_flags_ | kGCCallbackFlagsForExternalMemory); 1298 incremental_marking()->AdvanceIncrementalMarking( 1299 deadline, IncrementalMarking::GC_VIA_STACK_GUARD, StepOrigin::kV8); 1300 } 1301 } 1302 1303 void Heap::EnsureFillerObjectAtTop() { 1304 // There may be an allocation memento behind objects in new space. Upon 1305 // evacuation of a non-full new space (or if we are on the last page) there 1306 // may be uninitialized memory behind top. We fill the remainder of the page 1307 // with a filler. 1308 Address to_top = new_space_->top(); 1309 Page* page = Page::FromAddress(to_top - kPointerSize); 1310 if (page->Contains(to_top)) { 1311 int remaining_in_page = static_cast<int>(page->area_end() - to_top); 1312 CreateFillerObjectAt(to_top, remaining_in_page, ClearRecordedSlots::kNo); 1313 } 1314 } 1315 1316 bool Heap::CollectGarbage(AllocationSpace space, 1317 GarbageCollectionReason gc_reason, 1318 const v8::GCCallbackFlags gc_callback_flags) { 1319 const char* collector_reason = nullptr; 1320 GarbageCollector collector = SelectGarbageCollector(space, &collector_reason); 1321 1322 if (!CanExpandOldGeneration(new_space()->Capacity())) { 1323 InvokeNearHeapLimitCallback(); 1324 } 1325 1326 // Ensure that all pending phantom callbacks are invoked. 1327 isolate()->global_handles()->InvokeSecondPassPhantomCallbacks(); 1328 1329 // The VM is in the GC state until exiting this function. 1330 VMState<GC> state(isolate()); 1331 1332 #ifdef V8_ENABLE_ALLOCATION_TIMEOUT 1333 // Reset the allocation timeout, but make sure to allow at least a few 1334 // allocations after a collection. The reason for this is that we have a lot 1335 // of allocation sequences and we assume that a garbage collection will allow 1336 // the subsequent allocation attempts to go through. 1337 if (FLAG_random_gc_interval > 0 || FLAG_gc_interval >= 0) { 1338 allocation_timeout_ = Max(6, NextAllocationTimeout(allocation_timeout_)); 1339 } 1340 #endif 1341 1342 EnsureFillerObjectAtTop(); 1343 1344 if (IsYoungGenerationCollector(collector) && 1345 !incremental_marking()->IsStopped()) { 1346 if (FLAG_trace_incremental_marking) { 1347 isolate()->PrintWithTimestamp( 1348 "[IncrementalMarking] Scavenge during marking.\n"); 1349 } 1350 } 1351 1352 bool next_gc_likely_to_collect_more = false; 1353 size_t committed_memory_before = 0; 1354 1355 if (collector == MARK_COMPACTOR) { 1356 committed_memory_before = CommittedOldGenerationMemory(); 1357 } 1358 1359 { 1360 tracer()->Start(collector, gc_reason, collector_reason); 1361 DCHECK(AllowHeapAllocation::IsAllowed()); 1362 DisallowHeapAllocation no_allocation_during_gc; 1363 GarbageCollectionPrologue(); 1364 1365 { 1366 HistogramTimer* gc_type_timer = GCTypeTimer(collector); 1367 HistogramTimerScope histogram_timer_scope(gc_type_timer); 1368 TRACE_EVENT0("v8", gc_type_timer->name()); 1369 1370 HistogramTimer* gc_type_priority_timer = GCTypePriorityTimer(collector); 1371 OptionalHistogramTimerScopeMode mode = 1372 isolate_->IsMemorySavingsModeActive() 1373 ? OptionalHistogramTimerScopeMode::DONT_TAKE_TIME 1374 : OptionalHistogramTimerScopeMode::TAKE_TIME; 1375 OptionalHistogramTimerScope histogram_timer_priority_scope( 1376 gc_type_priority_timer, mode); 1377 1378 next_gc_likely_to_collect_more = 1379 PerformGarbageCollection(collector, gc_callback_flags); 1380 if (collector == MARK_COMPACTOR) { 1381 tracer()->RecordMarkCompactHistograms(gc_type_timer); 1382 } 1383 } 1384 1385 GarbageCollectionEpilogue(); 1386 if (collector == MARK_COMPACTOR && FLAG_track_detached_contexts) { 1387 isolate()->CheckDetachedContextsAfterGC(); 1388 } 1389 1390 if (collector == MARK_COMPACTOR) { 1391 size_t committed_memory_after = CommittedOldGenerationMemory(); 1392 size_t used_memory_after = OldGenerationSizeOfObjects(); 1393 MemoryReducer::Event event; 1394 event.type = MemoryReducer::kMarkCompact; 1395 event.time_ms = MonotonicallyIncreasingTimeInMs(); 1396 // Trigger one more GC if 1397 // - this GC decreased committed memory, 1398 // - there is high fragmentation, 1399 // - there are live detached contexts. 1400 event.next_gc_likely_to_collect_more = 1401 (committed_memory_before > committed_memory_after + MB) || 1402 HasHighFragmentation(used_memory_after, committed_memory_after) || 1403 (detached_contexts()->length() > 0); 1404 event.committed_memory = committed_memory_after; 1405 if (deserialization_complete_) { 1406 memory_reducer_->NotifyMarkCompact(event); 1407 } 1408 } 1409 1410 tracer()->Stop(collector); 1411 } 1412 1413 if (collector == MARK_COMPACTOR && 1414 (gc_callback_flags & (kGCCallbackFlagForced | 1415 kGCCallbackFlagCollectAllAvailableGarbage)) != 0) { 1416 isolate()->CountUsage(v8::Isolate::kForcedGC); 1417 } 1418 1419 // Start incremental marking for the next cycle. The heap snapshot 1420 // generator needs incremental marking to stay off after it aborted. 1421 // We do this only for scavenger to avoid a loop where mark-compact 1422 // causes another mark-compact. 1423 if (IsYoungGenerationCollector(collector) && 1424 !ShouldAbortIncrementalMarking()) { 1425 StartIncrementalMarkingIfAllocationLimitIsReached( 1426 GCFlagsForIncrementalMarking(), 1427 kGCCallbackScheduleIdleGarbageCollection); 1428 } 1429 1430 return next_gc_likely_to_collect_more; 1431 } 1432 1433 1434 int Heap::NotifyContextDisposed(bool dependant_context) { 1435 if (!dependant_context) { 1436 tracer()->ResetSurvivalEvents(); 1437 old_generation_size_configured_ = false; 1438 MemoryReducer::Event event; 1439 event.type = MemoryReducer::kPossibleGarbage; 1440 event.time_ms = MonotonicallyIncreasingTimeInMs(); 1441 memory_reducer_->NotifyPossibleGarbage(event); 1442 } 1443 isolate()->AbortConcurrentOptimization(BlockingBehavior::kDontBlock); 1444 1445 number_of_disposed_maps_ = retained_maps()->length(); 1446 tracer()->AddContextDisposalTime(MonotonicallyIncreasingTimeInMs()); 1447 return ++contexts_disposed_; 1448 } 1449 1450 void Heap::StartIncrementalMarking(int gc_flags, 1451 GarbageCollectionReason gc_reason, 1452 GCCallbackFlags gc_callback_flags) { 1453 DCHECK(incremental_marking()->IsStopped()); 1454 set_current_gc_flags(gc_flags); 1455 current_gc_callback_flags_ = gc_callback_flags; 1456 incremental_marking()->Start(gc_reason); 1457 } 1458 1459 void Heap::StartIncrementalMarkingIfAllocationLimitIsReached( 1460 int gc_flags, const GCCallbackFlags gc_callback_flags) { 1461 if (incremental_marking()->IsStopped()) { 1462 IncrementalMarkingLimit reached_limit = IncrementalMarkingLimitReached(); 1463 if (reached_limit == IncrementalMarkingLimit::kSoftLimit) { 1464 incremental_marking()->incremental_marking_job()->ScheduleTask(this); 1465 } else if (reached_limit == IncrementalMarkingLimit::kHardLimit) { 1466 StartIncrementalMarking(gc_flags, 1467 GarbageCollectionReason::kAllocationLimit, 1468 gc_callback_flags); 1469 } 1470 } 1471 } 1472 1473 void Heap::StartIdleIncrementalMarking( 1474 GarbageCollectionReason gc_reason, 1475 const GCCallbackFlags gc_callback_flags) { 1476 gc_idle_time_handler_->ResetNoProgressCounter(); 1477 StartIncrementalMarking(kReduceMemoryFootprintMask, gc_reason, 1478 gc_callback_flags); 1479 } 1480 1481 void Heap::MoveElements(FixedArray* array, int dst_index, int src_index, 1482 int len, WriteBarrierMode mode) { 1483 if (len == 0) return; 1484 1485 DCHECK(array->map() != ReadOnlyRoots(this).fixed_cow_array_map()); 1486 Object** dst = array->data_start() + dst_index; 1487 Object** src = array->data_start() + src_index; 1488 if (FLAG_concurrent_marking && incremental_marking()->IsMarking()) { 1489 if (dst < src) { 1490 for (int i = 0; i < len; i++) { 1491 base::AsAtomicPointer::Relaxed_Store( 1492 dst + i, base::AsAtomicPointer::Relaxed_Load(src + i)); 1493 } 1494 } else { 1495 for (int i = len - 1; i >= 0; i--) { 1496 base::AsAtomicPointer::Relaxed_Store( 1497 dst + i, base::AsAtomicPointer::Relaxed_Load(src + i)); 1498 } 1499 } 1500 } else { 1501 MemMove(dst, src, len * kPointerSize); 1502 } 1503 if (mode == SKIP_WRITE_BARRIER) return; 1504 FIXED_ARRAY_ELEMENTS_WRITE_BARRIER(this, array, dst_index, len); 1505 } 1506 1507 1508 #ifdef VERIFY_HEAP 1509 // Helper class for verifying the string table. 1510 class StringTableVerifier : public ObjectVisitor { 1511 public: 1512 explicit StringTableVerifier(Isolate* isolate) : isolate_(isolate) {} 1513 1514 void VisitPointers(HeapObject* host, Object** start, Object** end) override { 1515 // Visit all HeapObject pointers in [start, end). 1516 for (Object** p = start; p < end; p++) { 1517 DCHECK(!HasWeakHeapObjectTag(*p)); 1518 if ((*p)->IsHeapObject()) { 1519 HeapObject* object = HeapObject::cast(*p); 1520 // Check that the string is actually internalized. 1521 CHECK(object->IsTheHole(isolate_) || object->IsUndefined(isolate_) || 1522 object->IsInternalizedString()); 1523 } 1524 } 1525 } 1526 void VisitPointers(HeapObject* host, MaybeObject** start, 1527 MaybeObject** end) override { 1528 UNREACHABLE(); 1529 } 1530 1531 private: 1532 Isolate* isolate_; 1533 }; 1534 1535 static void VerifyStringTable(Isolate* isolate) { 1536 StringTableVerifier verifier(isolate); 1537 isolate->heap()->string_table()->IterateElements(&verifier); 1538 } 1539 #endif // VERIFY_HEAP 1540 1541 bool Heap::ReserveSpace(Reservation* reservations, std::vector<Address>* maps) { 1542 bool gc_performed = true; 1543 int counter = 0; 1544 static const int kThreshold = 20; 1545 while (gc_performed && counter++ < kThreshold) { 1546 gc_performed = false; 1547 for (int space = FIRST_SPACE; 1548 space < SerializerDeserializer::kNumberOfSpaces; space++) { 1549 Reservation* reservation = &reservations[space]; 1550 DCHECK_LE(1, reservation->size()); 1551 if (reservation->at(0).size == 0) { 1552 DCHECK_EQ(1, reservation->size()); 1553 continue; 1554 } 1555 bool perform_gc = false; 1556 if (space == MAP_SPACE) { 1557 // We allocate each map individually to avoid fragmentation. 1558 maps->clear(); 1559 DCHECK_LE(reservation->size(), 2); 1560 int reserved_size = 0; 1561 for (const Chunk& c : *reservation) reserved_size += c.size; 1562 DCHECK_EQ(0, reserved_size % Map::kSize); 1563 int num_maps = reserved_size / Map::kSize; 1564 for (int i = 0; i < num_maps; i++) { 1565 // The deserializer will update the skip list. 1566 AllocationResult allocation = map_space()->AllocateRawUnaligned( 1567 Map::kSize, PagedSpace::IGNORE_SKIP_LIST); 1568 HeapObject* free_space = nullptr; 1569 if (allocation.To(&free_space)) { 1570 // Mark with a free list node, in case we have a GC before 1571 // deserializing. 1572 Address free_space_address = free_space->address(); 1573 CreateFillerObjectAt(free_space_address, Map::kSize, 1574 ClearRecordedSlots::kNo); 1575 maps->push_back(free_space_address); 1576 } else { 1577 perform_gc = true; 1578 break; 1579 } 1580 } 1581 } else if (space == LO_SPACE) { 1582 // Just check that we can allocate during deserialization. 1583 DCHECK_LE(reservation->size(), 2); 1584 int reserved_size = 0; 1585 for (const Chunk& c : *reservation) reserved_size += c.size; 1586 perform_gc = !CanExpandOldGeneration(reserved_size); 1587 } else { 1588 for (auto& chunk : *reservation) { 1589 AllocationResult allocation; 1590 int size = chunk.size; 1591 DCHECK_LE(static_cast<size_t>(size), 1592 MemoryAllocator::PageAreaSize( 1593 static_cast<AllocationSpace>(space))); 1594 if (space == NEW_SPACE) { 1595 allocation = new_space()->AllocateRawUnaligned(size); 1596 } else { 1597 // The deserializer will update the skip list. 1598 allocation = paged_space(space)->AllocateRawUnaligned( 1599 size, PagedSpace::IGNORE_SKIP_LIST); 1600 } 1601 HeapObject* free_space = nullptr; 1602 if (allocation.To(&free_space)) { 1603 // Mark with a free list node, in case we have a GC before 1604 // deserializing. 1605 Address free_space_address = free_space->address(); 1606 CreateFillerObjectAt(free_space_address, size, 1607 ClearRecordedSlots::kNo); 1608 DCHECK_GT(SerializerDeserializer::kNumberOfPreallocatedSpaces, 1609 space); 1610 chunk.start = free_space_address; 1611 chunk.end = free_space_address + size; 1612 } else { 1613 perform_gc = true; 1614 break; 1615 } 1616 } 1617 } 1618 if (perform_gc) { 1619 // We cannot perfom a GC with an uninitialized isolate. This check 1620 // fails for example if the max old space size is chosen unwisely, 1621 // so that we cannot allocate space to deserialize the initial heap. 1622 if (!deserialization_complete_) { 1623 V8::FatalProcessOutOfMemory( 1624 isolate(), "insufficient memory to create an Isolate"); 1625 } 1626 if (space == NEW_SPACE) { 1627 CollectGarbage(NEW_SPACE, GarbageCollectionReason::kDeserializer); 1628 } else { 1629 if (counter > 1) { 1630 CollectAllGarbage( 1631 kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, 1632 GarbageCollectionReason::kDeserializer); 1633 } else { 1634 CollectAllGarbage(kAbortIncrementalMarkingMask, 1635 GarbageCollectionReason::kDeserializer); 1636 } 1637 } 1638 gc_performed = true; 1639 break; // Abort for-loop over spaces and retry. 1640 } 1641 } 1642 } 1643 1644 return !gc_performed; 1645 } 1646 1647 1648 void Heap::EnsureFromSpaceIsCommitted() { 1649 if (new_space_->CommitFromSpaceIfNeeded()) return; 1650 1651 // Committing memory to from space failed. 1652 // Memory is exhausted and we will die. 1653 FatalProcessOutOfMemory("Committing semi space failed."); 1654 } 1655 1656 1657 void Heap::UpdateSurvivalStatistics(int start_new_space_size) { 1658 if (start_new_space_size == 0) return; 1659 1660 promotion_ratio_ = (static_cast<double>(promoted_objects_size_) / 1661 static_cast<double>(start_new_space_size) * 100); 1662 1663 if (previous_semi_space_copied_object_size_ > 0) { 1664 promotion_rate_ = 1665 (static_cast<double>(promoted_objects_size_) / 1666 static_cast<double>(previous_semi_space_copied_object_size_) * 100); 1667 } else { 1668 promotion_rate_ = 0; 1669 } 1670 1671 semi_space_copied_rate_ = 1672 (static_cast<double>(semi_space_copied_object_size_) / 1673 static_cast<double>(start_new_space_size) * 100); 1674 1675 double survival_rate = promotion_ratio_ + semi_space_copied_rate_; 1676 tracer()->AddSurvivalRatio(survival_rate); 1677 } 1678 1679 bool Heap::PerformGarbageCollection( 1680 GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) { 1681 int freed_global_handles = 0; 1682 1683 if (!IsYoungGenerationCollector(collector)) { 1684 PROFILE(isolate_, CodeMovingGCEvent()); 1685 } 1686 1687 #ifdef VERIFY_HEAP 1688 if (FLAG_verify_heap) { 1689 VerifyStringTable(this->isolate()); 1690 } 1691 #endif 1692 1693 GCType gc_type = 1694 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge; 1695 1696 { 1697 GCCallbacksScope scope(this); 1698 if (scope.CheckReenter()) { 1699 AllowHeapAllocation allow_allocation; 1700 TRACE_GC(tracer(), GCTracer::Scope::HEAP_EXTERNAL_PROLOGUE); 1701 VMState<EXTERNAL> state(isolate_); 1702 HandleScope handle_scope(isolate_); 1703 CallGCPrologueCallbacks(gc_type, kNoGCCallbackFlags); 1704 } 1705 } 1706 1707 EnsureFromSpaceIsCommitted(); 1708 1709 size_t start_new_space_size = Heap::new_space()->Size(); 1710 1711 { 1712 Heap::SkipStoreBufferScope skip_store_buffer_scope(store_buffer_); 1713 1714 switch (collector) { 1715 case MARK_COMPACTOR: 1716 UpdateOldGenerationAllocationCounter(); 1717 // Perform mark-sweep with optional compaction. 1718 MarkCompact(); 1719 old_generation_size_configured_ = true; 1720 // This should be updated before PostGarbageCollectionProcessing, which 1721 // can cause another GC. Take into account the objects promoted during 1722 // GC. 1723 old_generation_allocation_counter_at_last_gc_ += 1724 static_cast<size_t>(promoted_objects_size_); 1725 old_generation_size_at_last_gc_ = OldGenerationSizeOfObjects(); 1726 break; 1727 case MINOR_MARK_COMPACTOR: 1728 MinorMarkCompact(); 1729 break; 1730 case SCAVENGER: 1731 if ((fast_promotion_mode_ && 1732 CanExpandOldGeneration(new_space()->Size()))) { 1733 tracer()->NotifyYoungGenerationHandling( 1734 YoungGenerationHandling::kFastPromotionDuringScavenge); 1735 EvacuateYoungGeneration(); 1736 } else { 1737 tracer()->NotifyYoungGenerationHandling( 1738 YoungGenerationHandling::kRegularScavenge); 1739 1740 Scavenge(); 1741 } 1742 break; 1743 } 1744 1745 ProcessPretenuringFeedback(); 1746 } 1747 1748 UpdateSurvivalStatistics(static_cast<int>(start_new_space_size)); 1749 ConfigureInitialOldGenerationSize(); 1750 1751 if (collector != MARK_COMPACTOR) { 1752 // Objects that died in the new space might have been accounted 1753 // as bytes marked ahead of schedule by the incremental marker. 1754 incremental_marking()->UpdateMarkedBytesAfterScavenge( 1755 start_new_space_size - SurvivedNewSpaceObjectSize()); 1756 } 1757 1758 if (!fast_promotion_mode_ || collector == MARK_COMPACTOR) { 1759 ComputeFastPromotionMode(); 1760 } 1761 1762 isolate_->counters()->objs_since_last_young()->Set(0); 1763 1764 gc_post_processing_depth_++; 1765 { 1766 AllowHeapAllocation allow_allocation; 1767 TRACE_GC(tracer(), GCTracer::Scope::HEAP_EXTERNAL_WEAK_GLOBAL_HANDLES); 1768 freed_global_handles = 1769 isolate_->global_handles()->PostGarbageCollectionProcessing( 1770 collector, gc_callback_flags); 1771 } 1772 gc_post_processing_depth_--; 1773 1774 isolate_->eternal_handles()->PostGarbageCollectionProcessing(); 1775 1776 // Update relocatables. 1777 Relocatable::PostGarbageCollectionProcessing(isolate_); 1778 1779 double gc_speed = tracer()->CombinedMarkCompactSpeedInBytesPerMillisecond(); 1780 double mutator_speed = 1781 tracer()->CurrentOldGenerationAllocationThroughputInBytesPerMillisecond(); 1782 size_t old_gen_size = OldGenerationSizeOfObjects(); 1783 if (collector == MARK_COMPACTOR) { 1784 // Register the amount of external allocated memory. 1785 external_memory_at_last_mark_compact_ = external_memory_; 1786 external_memory_limit_ = external_memory_ + kExternalAllocationSoftLimit; 1787 1788 size_t new_limit = heap_controller()->CalculateAllocationLimit( 1789 old_gen_size, max_old_generation_size_, gc_speed, mutator_speed, 1790 new_space()->Capacity(), CurrentHeapGrowingMode()); 1791 old_generation_allocation_limit_ = new_limit; 1792 1793 CheckIneffectiveMarkCompact( 1794 old_gen_size, tracer()->AverageMarkCompactMutatorUtilization()); 1795 } else if (HasLowYoungGenerationAllocationRate() && 1796 old_generation_size_configured_) { 1797 size_t new_limit = heap_controller()->CalculateAllocationLimit( 1798 old_gen_size, max_old_generation_size_, gc_speed, mutator_speed, 1799 new_space()->Capacity(), CurrentHeapGrowingMode()); 1800 if (new_limit < old_generation_allocation_limit_) { 1801 old_generation_allocation_limit_ = new_limit; 1802 } 1803 } 1804 1805 { 1806 GCCallbacksScope scope(this); 1807 if (scope.CheckReenter()) { 1808 AllowHeapAllocation allow_allocation; 1809 TRACE_GC(tracer(), GCTracer::Scope::HEAP_EXTERNAL_EPILOGUE); 1810 VMState<EXTERNAL> state(isolate_); 1811 HandleScope handle_scope(isolate_); 1812 CallGCEpilogueCallbacks(gc_type, gc_callback_flags); 1813 } 1814 } 1815 1816 #ifdef VERIFY_HEAP 1817 if (FLAG_verify_heap) { 1818 VerifyStringTable(this->isolate()); 1819 } 1820 #endif 1821 1822 return freed_global_handles > 0; 1823 } 1824 1825 1826 void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) { 1827 RuntimeCallTimerScope runtime_timer( 1828 isolate(), RuntimeCallCounterId::kGCPrologueCallback); 1829 for (const GCCallbackTuple& info : gc_prologue_callbacks_) { 1830 if (gc_type & info.gc_type) { 1831 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate()); 1832 info.callback(isolate, gc_type, flags, info.data); 1833 } 1834 } 1835 } 1836 1837 void Heap::CallGCEpilogueCallbacks(GCType gc_type, GCCallbackFlags flags) { 1838 RuntimeCallTimerScope runtime_timer( 1839 isolate(), RuntimeCallCounterId::kGCEpilogueCallback); 1840 for (const GCCallbackTuple& info : gc_epilogue_callbacks_) { 1841 if (gc_type & info.gc_type) { 1842 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate()); 1843 info.callback(isolate, gc_type, flags, info.data); 1844 } 1845 } 1846 } 1847 1848 1849 void Heap::MarkCompact() { 1850 PauseAllocationObserversScope pause_observers(this); 1851 1852 SetGCState(MARK_COMPACT); 1853 1854 LOG(isolate_, ResourceEvent("markcompact", "begin")); 1855 1856 uint64_t size_of_objects_before_gc = SizeOfObjects(); 1857 1858 CodeSpaceMemoryModificationScope code_modifcation(this); 1859 1860 mark_compact_collector()->Prepare(); 1861 1862 ms_count_++; 1863 1864 MarkCompactPrologue(); 1865 1866 mark_compact_collector()->CollectGarbage(); 1867 1868 LOG(isolate_, ResourceEvent("markcompact", "end")); 1869 1870 MarkCompactEpilogue(); 1871 1872 if (FLAG_allocation_site_pretenuring) { 1873 EvaluateOldSpaceLocalPretenuring(size_of_objects_before_gc); 1874 } 1875 } 1876 1877 void Heap::MinorMarkCompact() { 1878 #ifdef ENABLE_MINOR_MC 1879 DCHECK(FLAG_minor_mc); 1880 1881 PauseAllocationObserversScope pause_observers(this); 1882 SetGCState(MINOR_MARK_COMPACT); 1883 LOG(isolate_, ResourceEvent("MinorMarkCompact", "begin")); 1884 1885 TRACE_GC(tracer(), GCTracer::Scope::MINOR_MC); 1886 AlwaysAllocateScope always_allocate(isolate()); 1887 IncrementalMarking::PauseBlackAllocationScope pause_black_allocation( 1888 incremental_marking()); 1889 ConcurrentMarking::PauseScope pause_scope(concurrent_marking()); 1890 1891 minor_mark_compact_collector()->CollectGarbage(); 1892 1893 LOG(isolate_, ResourceEvent("MinorMarkCompact", "end")); 1894 SetGCState(NOT_IN_GC); 1895 #else 1896 UNREACHABLE(); 1897 #endif // ENABLE_MINOR_MC 1898 } 1899 1900 void Heap::MarkCompactEpilogue() { 1901 TRACE_GC(tracer(), GCTracer::Scope::MC_EPILOGUE); 1902 SetGCState(NOT_IN_GC); 1903 1904 isolate_->counters()->objs_since_last_full()->Set(0); 1905 1906 incremental_marking()->Epilogue(); 1907 1908 DCHECK(incremental_marking()->IsStopped()); 1909 } 1910 1911 1912 void Heap::MarkCompactPrologue() { 1913 TRACE_GC(tracer(), GCTracer::Scope::MC_PROLOGUE); 1914 isolate_->context_slot_cache()->Clear(); 1915 isolate_->descriptor_lookup_cache()->Clear(); 1916 RegExpResultsCache::Clear(string_split_cache()); 1917 RegExpResultsCache::Clear(regexp_multiple_cache()); 1918 1919 isolate_->compilation_cache()->MarkCompactPrologue(); 1920 1921 FlushNumberStringCache(); 1922 } 1923 1924 1925 void Heap::CheckNewSpaceExpansionCriteria() { 1926 if (FLAG_experimental_new_space_growth_heuristic) { 1927 if (new_space_->TotalCapacity() < new_space_->MaximumCapacity() && 1928 survived_last_scavenge_ * 100 / new_space_->TotalCapacity() >= 10) { 1929 // Grow the size of new space if there is room to grow, and more than 10% 1930 // have survived the last scavenge. 1931 new_space_->Grow(); 1932 survived_since_last_expansion_ = 0; 1933 } 1934 } else if (new_space_->TotalCapacity() < new_space_->MaximumCapacity() && 1935 survived_since_last_expansion_ > new_space_->TotalCapacity()) { 1936 // Grow the size of new space if there is room to grow, and enough data 1937 // has survived scavenge since the last expansion. 1938 new_space_->Grow(); 1939 survived_since_last_expansion_ = 0; 1940 } 1941 } 1942 1943 static bool IsUnscavengedHeapObject(Heap* heap, Object** p) { 1944 return Heap::InFromSpace(*p) && 1945 !HeapObject::cast(*p)->map_word().IsForwardingAddress(); 1946 } 1947 1948 class ScavengeWeakObjectRetainer : public WeakObjectRetainer { 1949 public: 1950 virtual Object* RetainAs(Object* object) { 1951 if (!Heap::InFromSpace(object)) { 1952 return object; 1953 } 1954 1955 MapWord map_word = HeapObject::cast(object)->map_word(); 1956 if (map_word.IsForwardingAddress()) { 1957 return map_word.ToForwardingAddress(); 1958 } 1959 return nullptr; 1960 } 1961 }; 1962 1963 void Heap::EvacuateYoungGeneration() { 1964 TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_FAST_PROMOTE); 1965 base::LockGuard<base::Mutex> guard(relocation_mutex()); 1966 ConcurrentMarking::PauseScope pause_scope(concurrent_marking()); 1967 if (!FLAG_concurrent_marking) { 1968 DCHECK(fast_promotion_mode_); 1969 DCHECK(CanExpandOldGeneration(new_space()->Size())); 1970 } 1971 1972 mark_compact_collector()->sweeper()->EnsureIterabilityCompleted(); 1973 1974 SetGCState(SCAVENGE); 1975 LOG(isolate_, ResourceEvent("scavenge", "begin")); 1976 1977 // Move pages from new->old generation. 1978 PageRange range(new_space()->first_allocatable_address(), new_space()->top()); 1979 for (auto it = range.begin(); it != range.end();) { 1980 Page* p = (*++it)->prev_page(); 1981 new_space()->from_space().RemovePage(p); 1982 Page::ConvertNewToOld(p); 1983 if (incremental_marking()->IsMarking()) 1984 mark_compact_collector()->RecordLiveSlotsOnPage(p); 1985 } 1986 1987 // Reset new space. 1988 if (!new_space()->Rebalance()) { 1989 FatalProcessOutOfMemory("NewSpace::Rebalance"); 1990 } 1991 new_space()->ResetLinearAllocationArea(); 1992 new_space()->set_age_mark(new_space()->top()); 1993 1994 // Fix up special trackers. 1995 external_string_table_.PromoteAllNewSpaceStrings(); 1996 // GlobalHandles are updated in PostGarbageCollectonProcessing 1997 1998 IncrementYoungSurvivorsCounter(new_space()->Size()); 1999 IncrementPromotedObjectsSize(new_space()->Size()); 2000 IncrementSemiSpaceCopiedObjectSize(0); 2001 2002 LOG(isolate_, ResourceEvent("scavenge", "end")); 2003 SetGCState(NOT_IN_GC); 2004 } 2005 2006 static bool IsLogging(Isolate* isolate) { 2007 return FLAG_verify_predictable || isolate->logger()->is_logging() || 2008 isolate->is_profiling() || 2009 (isolate->heap_profiler() != nullptr && 2010 isolate->heap_profiler()->is_tracking_object_moves()) || 2011 isolate->heap()->has_heap_object_allocation_tracker(); 2012 } 2013 2014 class PageScavengingItem final : public ItemParallelJob::Item { 2015 public: 2016 explicit PageScavengingItem(MemoryChunk* chunk) : chunk_(chunk) {} 2017 virtual ~PageScavengingItem() {} 2018 2019 void Process(Scavenger* scavenger) { scavenger->ScavengePage(chunk_); } 2020 2021 private: 2022 MemoryChunk* const chunk_; 2023 }; 2024 2025 class ScavengingTask final : public ItemParallelJob::Task { 2026 public: 2027 ScavengingTask(Heap* heap, Scavenger* scavenger, OneshotBarrier* barrier) 2028 : ItemParallelJob::Task(heap->isolate()), 2029 heap_(heap), 2030 scavenger_(scavenger), 2031 barrier_(barrier) {} 2032 2033 void RunInParallel() final { 2034 TRACE_BACKGROUND_GC( 2035 heap_->tracer(), 2036 GCTracer::BackgroundScope::SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL); 2037 double scavenging_time = 0.0; 2038 { 2039 barrier_->Start(); 2040 TimedScope scope(&scavenging_time); 2041 PageScavengingItem* item = nullptr; 2042 while ((item = GetItem<PageScavengingItem>()) != nullptr) { 2043 item->Process(scavenger_); 2044 item->MarkFinished(); 2045 } 2046 do { 2047 scavenger_->Process(barrier_); 2048 } while (!barrier_->Wait()); 2049 scavenger_->Process(); 2050 } 2051 if (FLAG_trace_parallel_scavenge) { 2052 PrintIsolate(heap_->isolate(), 2053 "scavenge[%p]: time=%.2f copied=%zu promoted=%zu\n", 2054 static_cast<void*>(this), scavenging_time, 2055 scavenger_->bytes_copied(), scavenger_->bytes_promoted()); 2056 } 2057 }; 2058 2059 private: 2060 Heap* const heap_; 2061 Scavenger* const scavenger_; 2062 OneshotBarrier* const barrier_; 2063 }; 2064 2065 int Heap::NumberOfScavengeTasks() { 2066 if (!FLAG_parallel_scavenge) return 1; 2067 const int num_scavenge_tasks = 2068 static_cast<int>(new_space()->TotalCapacity()) / MB; 2069 static int num_cores = V8::GetCurrentPlatform()->NumberOfWorkerThreads() + 1; 2070 int tasks = 2071 Max(1, Min(Min(num_scavenge_tasks, kMaxScavengerTasks), num_cores)); 2072 if (!CanExpandOldGeneration(static_cast<size_t>(tasks * Page::kPageSize))) { 2073 // Optimize for memory usage near the heap limit. 2074 tasks = 1; 2075 } 2076 return tasks; 2077 } 2078 2079 void Heap::Scavenge() { 2080 TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE); 2081 base::LockGuard<base::Mutex> guard(relocation_mutex()); 2082 ConcurrentMarking::PauseScope pause_scope(concurrent_marking()); 2083 // There are soft limits in the allocation code, designed to trigger a mark 2084 // sweep collection by failing allocations. There is no sense in trying to 2085 // trigger one during scavenge: scavenges allocation should always succeed. 2086 AlwaysAllocateScope scope(isolate()); 2087 2088 // Bump-pointer allocations done during scavenge are not real allocations. 2089 // Pause the inline allocation steps. 2090 PauseAllocationObserversScope pause_observers(this); 2091 2092 IncrementalMarking::PauseBlackAllocationScope pause_black_allocation( 2093 incremental_marking()); 2094 2095 2096 mark_compact_collector()->sweeper()->EnsureIterabilityCompleted(); 2097 2098 SetGCState(SCAVENGE); 2099 2100 // Implements Cheney's copying algorithm 2101 LOG(isolate_, ResourceEvent("scavenge", "begin")); 2102 2103 // Flip the semispaces. After flipping, to space is empty, from space has 2104 // live objects. 2105 new_space_->Flip(); 2106 new_space_->ResetLinearAllocationArea(); 2107 2108 ItemParallelJob job(isolate()->cancelable_task_manager(), 2109 ¶llel_scavenge_semaphore_); 2110 const int kMainThreadId = 0; 2111 Scavenger* scavengers[kMaxScavengerTasks]; 2112 const bool is_logging = IsLogging(isolate()); 2113 const int num_scavenge_tasks = NumberOfScavengeTasks(); 2114 OneshotBarrier barrier; 2115 Scavenger::CopiedList copied_list(num_scavenge_tasks); 2116 Scavenger::PromotionList promotion_list(num_scavenge_tasks); 2117 for (int i = 0; i < num_scavenge_tasks; i++) { 2118 scavengers[i] = 2119 new Scavenger(this, is_logging, &copied_list, &promotion_list, i); 2120 job.AddTask(new ScavengingTask(this, scavengers[i], &barrier)); 2121 } 2122 2123 { 2124 Sweeper* sweeper = mark_compact_collector()->sweeper(); 2125 // Pause the concurrent sweeper. 2126 Sweeper::PauseOrCompleteScope pause_scope(sweeper); 2127 // Filter out pages from the sweeper that need to be processed for old to 2128 // new slots by the Scavenger. After processing, the Scavenger adds back 2129 // pages that are still unsweeped. This way the Scavenger has exclusive 2130 // access to the slots of a page and can completely avoid any locks on 2131 // the page itself. 2132 Sweeper::FilterSweepingPagesScope filter_scope(sweeper, pause_scope); 2133 filter_scope.FilterOldSpaceSweepingPages( 2134 [](Page* page) { return !page->ContainsSlots<OLD_TO_NEW>(); }); 2135 RememberedSet<OLD_TO_NEW>::IterateMemoryChunks( 2136 this, [&job](MemoryChunk* chunk) { 2137 job.AddItem(new PageScavengingItem(chunk)); 2138 }); 2139 2140 RootScavengeVisitor root_scavenge_visitor(scavengers[kMainThreadId]); 2141 2142 { 2143 // Identify weak unmodified handles. Requires an unmodified graph. 2144 TRACE_GC( 2145 tracer(), 2146 GCTracer::Scope::SCAVENGER_SCAVENGE_WEAK_GLOBAL_HANDLES_IDENTIFY); 2147 isolate()->global_handles()->IdentifyWeakUnmodifiedObjects( 2148 &JSObject::IsUnmodifiedApiObject); 2149 } 2150 { 2151 // Copy roots. 2152 TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE_ROOTS); 2153 IterateRoots(&root_scavenge_visitor, VISIT_ALL_IN_SCAVENGE); 2154 } 2155 { 2156 // Parallel phase scavenging all copied and promoted objects. 2157 TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE_PARALLEL); 2158 job.Run(isolate()->async_counters()); 2159 DCHECK(copied_list.IsEmpty()); 2160 DCHECK(promotion_list.IsEmpty()); 2161 } 2162 { 2163 // Scavenge weak global handles. 2164 TRACE_GC(tracer(), 2165 GCTracer::Scope::SCAVENGER_SCAVENGE_WEAK_GLOBAL_HANDLES_PROCESS); 2166 isolate()->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending( 2167 &IsUnscavengedHeapObject); 2168 isolate() 2169 ->global_handles() 2170 ->IterateNewSpaceWeakUnmodifiedRootsForFinalizers( 2171 &root_scavenge_visitor); 2172 scavengers[kMainThreadId]->Process(); 2173 2174 DCHECK(copied_list.IsEmpty()); 2175 DCHECK(promotion_list.IsEmpty()); 2176 isolate() 2177 ->global_handles() 2178 ->IterateNewSpaceWeakUnmodifiedRootsForPhantomHandles( 2179 &root_scavenge_visitor, &IsUnscavengedHeapObject); 2180 } 2181 2182 for (int i = 0; i < num_scavenge_tasks; i++) { 2183 scavengers[i]->Finalize(); 2184 delete scavengers[i]; 2185 } 2186 } 2187 2188 { 2189 // Update references into new space 2190 TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE_UPDATE_REFS); 2191 UpdateNewSpaceReferencesInExternalStringTable( 2192 &UpdateNewSpaceReferenceInExternalStringTableEntry); 2193 2194 incremental_marking()->UpdateMarkingWorklistAfterScavenge(); 2195 } 2196 2197 if (FLAG_concurrent_marking) { 2198 // Ensure that concurrent marker does not track pages that are 2199 // going to be unmapped. 2200 for (Page* p : PageRange(new_space()->from_space().first_page(), nullptr)) { 2201 concurrent_marking()->ClearLiveness(p); 2202 } 2203 } 2204 2205 ScavengeWeakObjectRetainer weak_object_retainer; 2206 ProcessYoungWeakReferences(&weak_object_retainer); 2207 2208 // Set age mark. 2209 new_space_->set_age_mark(new_space_->top()); 2210 2211 { 2212 TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_PROCESS_ARRAY_BUFFERS); 2213 ArrayBufferTracker::PrepareToFreeDeadInNewSpace(this); 2214 } 2215 array_buffer_collector()->FreeAllocationsOnBackgroundThread(); 2216 2217 RememberedSet<OLD_TO_NEW>::IterateMemoryChunks(this, [](MemoryChunk* chunk) { 2218 if (chunk->SweepingDone()) { 2219 RememberedSet<OLD_TO_NEW>::FreeEmptyBuckets(chunk); 2220 } else { 2221 RememberedSet<OLD_TO_NEW>::PreFreeEmptyBuckets(chunk); 2222 } 2223 }); 2224 2225 // Update how much has survived scavenge. 2226 IncrementYoungSurvivorsCounter(SurvivedNewSpaceObjectSize()); 2227 2228 // Scavenger may find new wrappers by iterating objects promoted onto a black 2229 // page. 2230 local_embedder_heap_tracer()->RegisterWrappersWithRemoteTracer(); 2231 2232 LOG(isolate_, ResourceEvent("scavenge", "end")); 2233 2234 SetGCState(NOT_IN_GC); 2235 } 2236 2237 void Heap::ComputeFastPromotionMode() { 2238 const size_t survived_in_new_space = 2239 survived_last_scavenge_ * 100 / new_space_->Capacity(); 2240 fast_promotion_mode_ = 2241 !FLAG_optimize_for_size && FLAG_fast_promotion_new_space && 2242 !ShouldReduceMemory() && new_space_->IsAtMaximumCapacity() && 2243 survived_in_new_space >= kMinPromotedPercentForFastPromotionMode; 2244 if (FLAG_trace_gc_verbose && !FLAG_trace_gc_ignore_scavenger) { 2245 PrintIsolate( 2246 isolate(), "Fast promotion mode: %s survival rate: %" PRIuS "%%\n", 2247 fast_promotion_mode_ ? "true" : "false", survived_in_new_space); 2248 } 2249 } 2250 2251 void Heap::UnprotectAndRegisterMemoryChunk(MemoryChunk* chunk) { 2252 if (unprotected_memory_chunks_registry_enabled_) { 2253 base::LockGuard<base::Mutex> guard(&unprotected_memory_chunks_mutex_); 2254 if (unprotected_memory_chunks_.insert(chunk).second) { 2255 chunk->SetReadAndWritable(); 2256 } 2257 } 2258 } 2259 2260 void Heap::UnprotectAndRegisterMemoryChunk(HeapObject* object) { 2261 UnprotectAndRegisterMemoryChunk(MemoryChunk::FromAddress(object->address())); 2262 } 2263 2264 void Heap::UnregisterUnprotectedMemoryChunk(MemoryChunk* chunk) { 2265 unprotected_memory_chunks_.erase(chunk); 2266 } 2267 2268 void Heap::ProtectUnprotectedMemoryChunks() { 2269 DCHECK(unprotected_memory_chunks_registry_enabled_); 2270 for (auto chunk = unprotected_memory_chunks_.begin(); 2271 chunk != unprotected_memory_chunks_.end(); chunk++) { 2272 CHECK(memory_allocator()->IsMemoryChunkExecutable(*chunk)); 2273 (*chunk)->SetReadAndExecutable(); 2274 } 2275 unprotected_memory_chunks_.clear(); 2276 } 2277 2278 bool Heap::ExternalStringTable::Contains(HeapObject* obj) { 2279 for (size_t i = 0; i < new_space_strings_.size(); ++i) { 2280 if (new_space_strings_[i] == obj) return true; 2281 } 2282 for (size_t i = 0; i < old_space_strings_.size(); ++i) { 2283 if (old_space_strings_[i] == obj) return true; 2284 } 2285 return false; 2286 } 2287 2288 void Heap::ProcessMovedExternalString(Page* old_page, Page* new_page, 2289 ExternalString* string) { 2290 size_t size = string->ExternalPayloadSize(); 2291 new_page->IncrementExternalBackingStoreBytes( 2292 ExternalBackingStoreType::kExternalString, size); 2293 old_page->DecrementExternalBackingStoreBytes( 2294 ExternalBackingStoreType::kExternalString, size); 2295 } 2296 2297 String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, 2298 Object** p) { 2299 MapWord first_word = HeapObject::cast(*p)->map_word(); 2300 2301 if (!first_word.IsForwardingAddress()) { 2302 // Unreachable external string can be finalized. 2303 String* string = String::cast(*p); 2304 if (!string->IsExternalString()) { 2305 // Original external string has been internalized. 2306 DCHECK(string->IsThinString()); 2307 return nullptr; 2308 } 2309 heap->FinalizeExternalString(string); 2310 return nullptr; 2311 } 2312 2313 // String is still reachable. 2314 String* new_string = String::cast(first_word.ToForwardingAddress()); 2315 String* original_string = reinterpret_cast<String*>(*p); 2316 // The length of the original string is used to disambiguate the scenario 2317 // of a ThingString being forwarded to an ExternalString (which already exists 2318 // in the OLD space), and an ExternalString being forwarded to its promoted 2319 // copy. See Scavenger::EvacuateThinString. 2320 if (new_string->IsThinString() || original_string->length() == 0) { 2321 // Filtering Thin strings out of the external string table. 2322 return nullptr; 2323 } else if (new_string->IsExternalString()) { 2324 heap->ProcessMovedExternalString( 2325 Page::FromAddress(reinterpret_cast<Address>(*p)), 2326 Page::FromHeapObject(new_string), ExternalString::cast(new_string)); 2327 return new_string; 2328 } 2329 2330 // Internalization can replace external strings with non-external strings. 2331 return new_string->IsExternalString() ? new_string : nullptr; 2332 } 2333 2334 void Heap::ExternalStringTable::VerifyNewSpace() { 2335 #ifdef DEBUG 2336 std::set<String*> visited_map; 2337 std::map<MemoryChunk*, size_t> size_map; 2338 ExternalBackingStoreType type = ExternalBackingStoreType::kExternalString; 2339 for (size_t i = 0; i < new_space_strings_.size(); ++i) { 2340 String* obj = String::cast(new_space_strings_[i]); 2341 MemoryChunk* mc = MemoryChunk::FromHeapObject(obj); 2342 DCHECK(mc->InNewSpace()); 2343 DCHECK(heap_->InNewSpace(obj)); 2344 DCHECK(!obj->IsTheHole(heap_->isolate())); 2345 DCHECK(obj->IsExternalString()); 2346 // Note: we can have repeated elements in the table. 2347 DCHECK_EQ(0, visited_map.count(obj)); 2348 visited_map.insert(obj); 2349 size_map[mc] += ExternalString::cast(obj)->ExternalPayloadSize(); 2350 } 2351 for (std::map<MemoryChunk*, size_t>::iterator it = size_map.begin(); 2352 it != size_map.end(); it++) 2353 DCHECK_EQ(it->first->ExternalBackingStoreBytes(type), it->second); 2354 #endif 2355 } 2356 2357 void Heap::ExternalStringTable::Verify() { 2358 #ifdef DEBUG 2359 std::set<String*> visited_map; 2360 std::map<MemoryChunk*, size_t> size_map; 2361 ExternalBackingStoreType type = ExternalBackingStoreType::kExternalString; 2362 VerifyNewSpace(); 2363 for (size_t i = 0; i < old_space_strings_.size(); ++i) { 2364 String* obj = String::cast(old_space_strings_[i]); 2365 MemoryChunk* mc = MemoryChunk::FromHeapObject(obj); 2366 DCHECK(!mc->InNewSpace()); 2367 DCHECK(!heap_->InNewSpace(obj)); 2368 DCHECK(!obj->IsTheHole(heap_->isolate())); 2369 DCHECK(obj->IsExternalString()); 2370 // Note: we can have repeated elements in the table. 2371 DCHECK_EQ(0, visited_map.count(obj)); 2372 visited_map.insert(obj); 2373 size_map[mc] += ExternalString::cast(obj)->ExternalPayloadSize(); 2374 } 2375 for (std::map<MemoryChunk*, size_t>::iterator it = size_map.begin(); 2376 it != size_map.end(); it++) 2377 DCHECK_EQ(it->first->ExternalBackingStoreBytes(type), it->second); 2378 #endif 2379 } 2380 2381 void Heap::ExternalStringTable::UpdateNewSpaceReferences( 2382 Heap::ExternalStringTableUpdaterCallback updater_func) { 2383 if (new_space_strings_.empty()) return; 2384 2385 Object** start = new_space_strings_.data(); 2386 Object** end = start + new_space_strings_.size(); 2387 Object** last = start; 2388 2389 for (Object** p = start; p < end; ++p) { 2390 String* target = updater_func(heap_, p); 2391 2392 if (target == nullptr) continue; 2393 2394 DCHECK(target->IsExternalString()); 2395 2396 if (InNewSpace(target)) { 2397 // String is still in new space. Update the table entry. 2398 *last = target; 2399 ++last; 2400 } else { 2401 // String got promoted. Move it to the old string list. 2402 old_space_strings_.push_back(target); 2403 } 2404 } 2405 2406 DCHECK_LE(last, end); 2407 new_space_strings_.resize(static_cast<size_t>(last - start)); 2408 #ifdef VERIFY_HEAP 2409 if (FLAG_verify_heap) { 2410 VerifyNewSpace(); 2411 } 2412 #endif 2413 } 2414 2415 void Heap::ExternalStringTable::PromoteAllNewSpaceStrings() { 2416 old_space_strings_.reserve(old_space_strings_.size() + 2417 new_space_strings_.size()); 2418 std::move(std::begin(new_space_strings_), std::end(new_space_strings_), 2419 std::back_inserter(old_space_strings_)); 2420 new_space_strings_.clear(); 2421 } 2422 2423 void Heap::ExternalStringTable::IterateNewSpaceStrings(RootVisitor* v) { 2424 if (!new_space_strings_.empty()) { 2425 v->VisitRootPointers(Root::kExternalStringsTable, nullptr, 2426 new_space_strings_.data(), 2427 new_space_strings_.data() + new_space_strings_.size()); 2428 } 2429 } 2430 2431 void Heap::ExternalStringTable::IterateAll(RootVisitor* v) { 2432 IterateNewSpaceStrings(v); 2433 if (!old_space_strings_.empty()) { 2434 v->VisitRootPointers(Root::kExternalStringsTable, nullptr, 2435 old_space_strings_.data(), 2436 old_space_strings_.data() + old_space_strings_.size()); 2437 } 2438 } 2439 2440 void Heap::UpdateNewSpaceReferencesInExternalStringTable( 2441 ExternalStringTableUpdaterCallback updater_func) { 2442 external_string_table_.UpdateNewSpaceReferences(updater_func); 2443 } 2444 2445 void Heap::ExternalStringTable::UpdateReferences( 2446 Heap::ExternalStringTableUpdaterCallback updater_func) { 2447 if (old_space_strings_.size() > 0) { 2448 Object** start = old_space_strings_.data(); 2449 Object** end = start + old_space_strings_.size(); 2450 for (Object** p = start; p < end; ++p) *p = updater_func(heap_, p); 2451 } 2452 2453 UpdateNewSpaceReferences(updater_func); 2454 } 2455 2456 void Heap::UpdateReferencesInExternalStringTable( 2457 ExternalStringTableUpdaterCallback updater_func) { 2458 external_string_table_.UpdateReferences(updater_func); 2459 } 2460 2461 2462 void Heap::ProcessAllWeakReferences(WeakObjectRetainer* retainer) { 2463 ProcessNativeContexts(retainer); 2464 ProcessAllocationSites(retainer); 2465 } 2466 2467 2468 void Heap::ProcessYoungWeakReferences(WeakObjectRetainer* retainer) { 2469 ProcessNativeContexts(retainer); 2470 } 2471 2472 2473 void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer) { 2474 Object* head = VisitWeakList<Context>(this, native_contexts_list(), retainer); 2475 // Update the head of the list of contexts. 2476 set_native_contexts_list(head); 2477 } 2478 2479 2480 void Heap::ProcessAllocationSites(WeakObjectRetainer* retainer) { 2481 Object* allocation_site_obj = 2482 VisitWeakList<AllocationSite>(this, allocation_sites_list(), retainer); 2483 set_allocation_sites_list(allocation_site_obj); 2484 } 2485 2486 void Heap::ProcessWeakListRoots(WeakObjectRetainer* retainer) { 2487 set_native_contexts_list(retainer->RetainAs(native_contexts_list())); 2488 set_allocation_sites_list(retainer->RetainAs(allocation_sites_list())); 2489 } 2490 2491 void Heap::ForeachAllocationSite(Object* list, 2492 std::function<void(AllocationSite*)> visitor) { 2493 DisallowHeapAllocation disallow_heap_allocation; 2494 Object* current = list; 2495 while (current->IsAllocationSite()) { 2496 AllocationSite* site = AllocationSite::cast(current); 2497 visitor(site); 2498 Object* current_nested = site->nested_site(); 2499 while (current_nested->IsAllocationSite()) { 2500 AllocationSite* nested_site = AllocationSite::cast(current_nested); 2501 visitor(nested_site); 2502 current_nested = nested_site->nested_site(); 2503 } 2504 current = site->weak_next(); 2505 } 2506 } 2507 2508 void Heap::ResetAllAllocationSitesDependentCode(PretenureFlag flag) { 2509 DisallowHeapAllocation no_allocation_scope; 2510 bool marked = false; 2511 2512 ForeachAllocationSite(allocation_sites_list(), 2513 [&marked, flag, this](AllocationSite* site) { 2514 if (site->GetPretenureMode() == flag) { 2515 site->ResetPretenureDecision(); 2516 site->set_deopt_dependent_code(true); 2517 marked = true; 2518 RemoveAllocationSitePretenuringFeedback(site); 2519 return; 2520 } 2521 }); 2522 if (marked) isolate_->stack_guard()->RequestDeoptMarkedAllocationSites(); 2523 } 2524 2525 2526 void Heap::EvaluateOldSpaceLocalPretenuring( 2527 uint64_t size_of_objects_before_gc) { 2528 uint64_t size_of_objects_after_gc = SizeOfObjects(); 2529 double old_generation_survival_rate = 2530 (static_cast<double>(size_of_objects_after_gc) * 100) / 2531 static_cast<double>(size_of_objects_before_gc); 2532 2533 if (old_generation_survival_rate < kOldSurvivalRateLowThreshold) { 2534 // Too many objects died in the old generation, pretenuring of wrong 2535 // allocation sites may be the cause for that. We have to deopt all 2536 // dependent code registered in the allocation sites to re-evaluate 2537 // our pretenuring decisions. 2538 ResetAllAllocationSitesDependentCode(TENURED); 2539 if (FLAG_trace_pretenuring) { 2540 PrintF( 2541 "Deopt all allocation sites dependent code due to low survival " 2542 "rate in the old generation %f\n", 2543 old_generation_survival_rate); 2544 } 2545 } 2546 } 2547 2548 2549 void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) { 2550 DisallowHeapAllocation no_allocation; 2551 // All external strings are listed in the external string table. 2552 2553 class ExternalStringTableVisitorAdapter : public RootVisitor { 2554 public: 2555 explicit ExternalStringTableVisitorAdapter( 2556 Isolate* isolate, v8::ExternalResourceVisitor* visitor) 2557 : isolate_(isolate), visitor_(visitor) {} 2558 virtual void VisitRootPointers(Root root, const char* description, 2559 Object** start, Object** end) { 2560 for (Object** p = start; p < end; p++) { 2561 DCHECK((*p)->IsExternalString()); 2562 visitor_->VisitExternalString( 2563 Utils::ToLocal(Handle<String>(String::cast(*p), isolate_))); 2564 } 2565 } 2566 2567 private: 2568 Isolate* isolate_; 2569 v8::ExternalResourceVisitor* visitor_; 2570 } external_string_table_visitor(isolate(), visitor); 2571 2572 external_string_table_.IterateAll(&external_string_table_visitor); 2573 } 2574 2575 STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == 2576 0); // NOLINT 2577 STATIC_ASSERT((FixedTypedArrayBase::kDataOffset & kDoubleAlignmentMask) == 2578 0); // NOLINT 2579 #ifdef V8_HOST_ARCH_32_BIT 2580 STATIC_ASSERT((HeapNumber::kValueOffset & kDoubleAlignmentMask) != 2581 0); // NOLINT 2582 #endif 2583 2584 2585 int Heap::GetMaximumFillToAlign(AllocationAlignment alignment) { 2586 switch (alignment) { 2587 case kWordAligned: 2588 return 0; 2589 case kDoubleAligned: 2590 case kDoubleUnaligned: 2591 return kDoubleSize - kPointerSize; 2592 default: 2593 UNREACHABLE(); 2594 } 2595 return 0; 2596 } 2597 2598 2599 int Heap::GetFillToAlign(Address address, AllocationAlignment alignment) { 2600 intptr_t offset = OffsetFrom(address); 2601 if (alignment == kDoubleAligned && (offset & kDoubleAlignmentMask) != 0) 2602 return kPointerSize; 2603 if (alignment == kDoubleUnaligned && (offset & kDoubleAlignmentMask) == 0) 2604 return kDoubleSize - kPointerSize; // No fill if double is always aligned. 2605 return 0; 2606 } 2607 2608 2609 HeapObject* Heap::PrecedeWithFiller(HeapObject* object, int filler_size) { 2610 CreateFillerObjectAt(object->address(), filler_size, ClearRecordedSlots::kNo); 2611 return HeapObject::FromAddress(object->address() + filler_size); 2612 } 2613 2614 2615 HeapObject* Heap::AlignWithFiller(HeapObject* object, int object_size, 2616 int allocation_size, 2617 AllocationAlignment alignment) { 2618 int filler_size = allocation_size - object_size; 2619 DCHECK_LT(0, filler_size); 2620 int pre_filler = GetFillToAlign(object->address(), alignment); 2621 if (pre_filler) { 2622 object = PrecedeWithFiller(object, pre_filler); 2623 filler_size -= pre_filler; 2624 } 2625 if (filler_size) 2626 CreateFillerObjectAt(object->address() + object_size, filler_size, 2627 ClearRecordedSlots::kNo); 2628 return object; 2629 } 2630 2631 void Heap::RegisterNewArrayBuffer(JSArrayBuffer* buffer) { 2632 ArrayBufferTracker::RegisterNew(this, buffer); 2633 } 2634 2635 2636 void Heap::UnregisterArrayBuffer(JSArrayBuffer* buffer) { 2637 ArrayBufferTracker::Unregister(this, buffer); 2638 } 2639 2640 void Heap::ConfigureInitialOldGenerationSize() { 2641 if (!old_generation_size_configured_ && tracer()->SurvivalEventsRecorded()) { 2642 old_generation_allocation_limit_ = 2643 Max(heap_controller()->MinimumAllocationLimitGrowingStep( 2644 CurrentHeapGrowingMode()), 2645 static_cast<size_t>( 2646 static_cast<double>(old_generation_allocation_limit_) * 2647 (tracer()->AverageSurvivalRatio() / 100))); 2648 } 2649 } 2650 2651 void Heap::CreateJSEntryStub() { 2652 JSEntryStub stub(isolate(), StackFrame::ENTRY); 2653 set_js_entry_code(*stub.GetCode()); 2654 } 2655 2656 2657 void Heap::CreateJSConstructEntryStub() { 2658 JSEntryStub stub(isolate(), StackFrame::CONSTRUCT_ENTRY); 2659 set_js_construct_entry_code(*stub.GetCode()); 2660 } 2661 2662 void Heap::CreateJSRunMicrotasksEntryStub() { 2663 JSEntryStub stub(isolate(), JSEntryStub::SpecialTarget::kRunMicrotasks); 2664 set_js_run_microtasks_entry_code(*stub.GetCode()); 2665 } 2666 2667 void Heap::CreateFixedStubs() { 2668 // Here we create roots for fixed stubs. They are needed at GC 2669 // for cooking and uncooking (check out frames.cc). 2670 // The eliminates the need for doing dictionary lookup in the 2671 // stub cache for these stubs. 2672 HandleScope scope(isolate()); 2673 // Canonicalize handles, so that we can share constant pool entries pointing 2674 // to code targets without dereferencing their handles. 2675 CanonicalHandleScope canonical(isolate()); 2676 2677 // Create stubs that should be there, so we don't unexpectedly have to 2678 // create them if we need them during the creation of another stub. 2679 // Stub creation mixes raw pointers and handles in an unsafe manner so 2680 // we cannot create stubs while we are creating stubs. 2681 CodeStub::GenerateStubsAheadOfTime(isolate()); 2682 2683 // gcc-4.4 has problem generating correct code of following snippet: 2684 // { JSEntryStub stub; 2685 // js_entry_code_ = *stub.GetCode(); 2686 // } 2687 // { JSConstructEntryStub stub; 2688 // js_construct_entry_code_ = *stub.GetCode(); 2689 // } 2690 // To workaround the problem, make separate functions without inlining. 2691 Heap::CreateJSEntryStub(); 2692 Heap::CreateJSConstructEntryStub(); 2693 Heap::CreateJSRunMicrotasksEntryStub(); 2694 } 2695 2696 bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) { 2697 switch (root_index) { 2698 case kNumberStringCacheRootIndex: 2699 case kCodeStubsRootIndex: 2700 case kScriptListRootIndex: 2701 case kMaterializedObjectsRootIndex: 2702 case kMicrotaskQueueRootIndex: 2703 case kDetachedContextsRootIndex: 2704 case kRetainedMapsRootIndex: 2705 case kRetainingPathTargetsRootIndex: 2706 case kFeedbackVectorsForProfilingToolsRootIndex: 2707 case kNoScriptSharedFunctionInfosRootIndex: 2708 case kSerializedObjectsRootIndex: 2709 case kSerializedGlobalProxySizesRootIndex: 2710 case kPublicSymbolTableRootIndex: 2711 case kApiSymbolTableRootIndex: 2712 case kApiPrivateSymbolTableRootIndex: 2713 case kMessageListenersRootIndex: 2714 case kDeserializeLazyHandlerRootIndex: 2715 case kDeserializeLazyHandlerWideRootIndex: 2716 case kDeserializeLazyHandlerExtraWideRootIndex: 2717 // Smi values 2718 #define SMI_ENTRY(type, name, Name) case k##Name##RootIndex: 2719 SMI_ROOT_LIST(SMI_ENTRY) 2720 #undef SMI_ENTRY 2721 // String table 2722 case kStringTableRootIndex: 2723 return true; 2724 2725 default: 2726 return false; 2727 } 2728 } 2729 2730 bool Heap::RootCanBeTreatedAsConstant(RootListIndex root_index) { 2731 bool can_be = !RootCanBeWrittenAfterInitialization(root_index) && 2732 !InNewSpace(root(root_index)); 2733 DCHECK_IMPLIES(can_be, IsImmovable(HeapObject::cast(root(root_index)))); 2734 return can_be; 2735 } 2736 2737 2738 void Heap::FlushNumberStringCache() { 2739 // Flush the number to string cache. 2740 int len = number_string_cache()->length(); 2741 for (int i = 0; i < len; i++) { 2742 number_string_cache()->set_undefined(i); 2743 } 2744 } 2745 2746 namespace { 2747 2748 Heap::RootListIndex RootIndexForFixedTypedArray(ExternalArrayType array_type) { 2749 switch (array_type) { 2750 #define ARRAY_TYPE_TO_ROOT_INDEX(Type, type, TYPE, ctype) \ 2751 case kExternal##Type##Array: \ 2752 return Heap::kFixed##Type##ArrayMapRootIndex; 2753 2754 TYPED_ARRAYS(ARRAY_TYPE_TO_ROOT_INDEX) 2755 #undef ARRAY_TYPE_TO_ROOT_INDEX 2756 } 2757 UNREACHABLE(); 2758 } 2759 2760 Heap::RootListIndex RootIndexForFixedTypedArray(ElementsKind elements_kind) { 2761 switch (elements_kind) { 2762 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \ 2763 case TYPE##_ELEMENTS: \ 2764 return Heap::kFixed##Type##ArrayMapRootIndex; 2765 TYPED_ARRAYS(TYPED_ARRAY_CASE) 2766 default: 2767 UNREACHABLE(); 2768 #undef TYPED_ARRAY_CASE 2769 } 2770 } 2771 2772 Heap::RootListIndex RootIndexForEmptyFixedTypedArray( 2773 ElementsKind elements_kind) { 2774 switch (elements_kind) { 2775 #define ELEMENT_KIND_TO_ROOT_INDEX(Type, type, TYPE, ctype) \ 2776 case TYPE##_ELEMENTS: \ 2777 return Heap::kEmptyFixed##Type##ArrayRootIndex; 2778 2779 TYPED_ARRAYS(ELEMENT_KIND_TO_ROOT_INDEX) 2780 #undef ELEMENT_KIND_TO_ROOT_INDEX 2781 default: 2782 UNREACHABLE(); 2783 } 2784 } 2785 2786 } // namespace 2787 2788 Map* Heap::MapForFixedTypedArray(ExternalArrayType array_type) { 2789 return Map::cast(roots_[RootIndexForFixedTypedArray(array_type)]); 2790 } 2791 2792 Map* Heap::MapForFixedTypedArray(ElementsKind elements_kind) { 2793 return Map::cast(roots_[RootIndexForFixedTypedArray(elements_kind)]); 2794 } 2795 2796 FixedTypedArrayBase* Heap::EmptyFixedTypedArrayForMap(const Map* map) { 2797 return FixedTypedArrayBase::cast( 2798 roots_[RootIndexForEmptyFixedTypedArray(map->elements_kind())]); 2799 } 2800 2801 HeapObject* Heap::CreateFillerObjectAt(Address addr, int size, 2802 ClearRecordedSlots clear_slots_mode, 2803 ClearFreedMemoryMode clear_memory_mode) { 2804 if (size == 0) return nullptr; 2805 HeapObject* filler = HeapObject::FromAddress(addr); 2806 if (size == kPointerSize) { 2807 filler->set_map_after_allocation( 2808 reinterpret_cast<Map*>(root(kOnePointerFillerMapRootIndex)), 2809 SKIP_WRITE_BARRIER); 2810 } else if (size == 2 * kPointerSize) { 2811 filler->set_map_after_allocation( 2812 reinterpret_cast<Map*>(root(kTwoPointerFillerMapRootIndex)), 2813 SKIP_WRITE_BARRIER); 2814 if (clear_memory_mode == ClearFreedMemoryMode::kClearFreedMemory) { 2815 Memory<Address>(addr + kPointerSize) = 2816 static_cast<Address>(kClearedFreeMemoryValue); 2817 } 2818 } else { 2819 DCHECK_GT(size, 2 * kPointerSize); 2820 filler->set_map_after_allocation( 2821 reinterpret_cast<Map*>(root(kFreeSpaceMapRootIndex)), 2822 SKIP_WRITE_BARRIER); 2823 FreeSpace::cast(filler)->relaxed_write_size(size); 2824 if (clear_memory_mode == ClearFreedMemoryMode::kClearFreedMemory) { 2825 memset(reinterpret_cast<void*>(addr + 2 * kPointerSize), 2826 kClearedFreeMemoryValue, size - 2 * kPointerSize); 2827 } 2828 } 2829 if (clear_slots_mode == ClearRecordedSlots::kYes) { 2830 ClearRecordedSlotRange(addr, addr + size); 2831 } 2832 2833 // At this point, we may be deserializing the heap from a snapshot, and 2834 // none of the maps have been created yet and are nullptr. 2835 DCHECK((filler->map() == nullptr && !deserialization_complete_) || 2836 filler->map()->IsMap()); 2837 return filler; 2838 } 2839 2840 2841 bool Heap::CanMoveObjectStart(HeapObject* object) { 2842 if (!FLAG_move_object_start) return false; 2843 2844 // Sampling heap profiler may have a reference to the object. 2845 if (isolate()->heap_profiler()->is_sampling_allocations()) return false; 2846 2847 Address address = object->address(); 2848 2849 if (lo_space()->Contains(object)) return false; 2850 2851 // We can move the object start if the page was already swept. 2852 return Page::FromAddress(address)->SweepingDone(); 2853 } 2854 2855 bool Heap::IsImmovable(HeapObject* object) { 2856 MemoryChunk* chunk = MemoryChunk::FromAddress(object->address()); 2857 return chunk->NeverEvacuate() || chunk->owner()->identity() == LO_SPACE; 2858 } 2859 2860 #ifdef ENABLE_SLOW_DCHECKS 2861 namespace { 2862 2863 class LeftTrimmerVerifierRootVisitor : public RootVisitor { 2864 public: 2865 explicit LeftTrimmerVerifierRootVisitor(FixedArrayBase* to_check) 2866 : to_check_(to_check) {} 2867 2868 virtual void VisitRootPointers(Root root, const char* description, 2869 Object** start, Object** end) { 2870 for (Object** p = start; p < end; ++p) { 2871 DCHECK_NE(*p, to_check_); 2872 } 2873 } 2874 2875 private: 2876 FixedArrayBase* to_check_; 2877 2878 DISALLOW_COPY_AND_ASSIGN(LeftTrimmerVerifierRootVisitor); 2879 }; 2880 } // namespace 2881 #endif // ENABLE_SLOW_DCHECKS 2882 2883 namespace { 2884 bool MayContainRecordedSlots(HeapObject* object) { 2885 // New space object do not have recorded slots. 2886 if (MemoryChunk::FromHeapObject(object)->InNewSpace()) return false; 2887 // Whitelist objects that definitely do not have pointers. 2888 if (object->IsByteArray() || object->IsFixedDoubleArray()) return false; 2889 // Conservatively return true for other objects. 2890 return true; 2891 } 2892 } // namespace 2893 2894 FixedArrayBase* Heap::LeftTrimFixedArray(FixedArrayBase* object, 2895 int elements_to_trim) { 2896 if (elements_to_trim == 0) { 2897 // This simplifies reasoning in the rest of the function. 2898 return object; 2899 } 2900 CHECK_NOT_NULL(object); 2901 DCHECK(CanMoveObjectStart(object)); 2902 // Add custom visitor to concurrent marker if new left-trimmable type 2903 // is added. 2904 DCHECK(object->IsFixedArray() || object->IsFixedDoubleArray()); 2905 const int element_size = object->IsFixedArray() ? kPointerSize : kDoubleSize; 2906 const int bytes_to_trim = elements_to_trim * element_size; 2907 Map* map = object->map(); 2908 2909 // For now this trick is only applied to objects in new and paged space. 2910 // In large object space the object's start must coincide with chunk 2911 // and thus the trick is just not applicable. 2912 DCHECK(!lo_space()->Contains(object)); 2913 DCHECK(object->map() != ReadOnlyRoots(this).fixed_cow_array_map()); 2914 2915 STATIC_ASSERT(FixedArrayBase::kMapOffset == 0); 2916 STATIC_ASSERT(FixedArrayBase::kLengthOffset == kPointerSize); 2917 STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize); 2918 2919 const int len = object->length(); 2920 DCHECK(elements_to_trim <= len); 2921 2922 // Calculate location of new array start. 2923 Address old_start = object->address(); 2924 Address new_start = old_start + bytes_to_trim; 2925 2926 if (incremental_marking()->IsMarking()) { 2927 incremental_marking()->NotifyLeftTrimming( 2928 object, HeapObject::FromAddress(new_start)); 2929 } 2930 2931 // Technically in new space this write might be omitted (except for 2932 // debug mode which iterates through the heap), but to play safer 2933 // we still do it. 2934 HeapObject* filler = 2935 CreateFillerObjectAt(old_start, bytes_to_trim, ClearRecordedSlots::kYes); 2936 2937 // Initialize header of the trimmed array. Since left trimming is only 2938 // performed on pages which are not concurrently swept creating a filler 2939 // object does not require synchronization. 2940 RELAXED_WRITE_FIELD(object, bytes_to_trim, map); 2941 RELAXED_WRITE_FIELD(object, bytes_to_trim + kPointerSize, 2942 Smi::FromInt(len - elements_to_trim)); 2943 2944 FixedArrayBase* new_object = 2945 FixedArrayBase::cast(HeapObject::FromAddress(new_start)); 2946 2947 // Remove recorded slots for the new map and length offset. 2948 ClearRecordedSlot(new_object, HeapObject::RawField(new_object, 0)); 2949 ClearRecordedSlot(new_object, HeapObject::RawField( 2950 new_object, FixedArrayBase::kLengthOffset)); 2951 2952 // Handle invalidated old-to-old slots. 2953 if (incremental_marking()->IsCompacting() && 2954 MayContainRecordedSlots(new_object)) { 2955 // If the array was right-trimmed before, then it is registered in 2956 // the invalidated_slots. 2957 MemoryChunk::FromHeapObject(new_object) 2958 ->MoveObjectWithInvalidatedSlots(filler, new_object); 2959 // We have to clear slots in the free space to avoid stale old-to-old slots. 2960 // Note we cannot use ClearFreedMemoryMode of CreateFillerObjectAt because 2961 // we need pointer granularity writes to avoid race with the concurrent 2962 // marking. 2963 if (filler->Size() > FreeSpace::kSize) { 2964 MemsetPointer(HeapObject::RawField(filler, FreeSpace::kSize), 2965 ReadOnlyRoots(this).undefined_value(), 2966 (filler->Size() - FreeSpace::kSize) / kPointerSize); 2967 } 2968 } 2969 // Notify the heap profiler of change in object layout. 2970 OnMoveEvent(new_object, object, new_object->Size()); 2971 2972 #ifdef ENABLE_SLOW_DCHECKS 2973 if (FLAG_enable_slow_asserts) { 2974 // Make sure the stack or other roots (e.g., Handles) don't contain pointers 2975 // to the original FixedArray (which is now the filler object). 2976 LeftTrimmerVerifierRootVisitor root_visitor(object); 2977 IterateRoots(&root_visitor, VISIT_ALL); 2978 } 2979 #endif // ENABLE_SLOW_DCHECKS 2980 2981 return new_object; 2982 } 2983 2984 void Heap::RightTrimFixedArray(FixedArrayBase* object, int elements_to_trim) { 2985 const int len = object->length(); 2986 DCHECK_LE(elements_to_trim, len); 2987 DCHECK_GE(elements_to_trim, 0); 2988 2989 int bytes_to_trim; 2990 DCHECK(!object->IsFixedTypedArrayBase()); 2991 if (object->IsByteArray()) { 2992 int new_size = ByteArray::SizeFor(len - elements_to_trim); 2993 bytes_to_trim = ByteArray::SizeFor(len) - new_size; 2994 DCHECK_GE(bytes_to_trim, 0); 2995 } else if (object->IsFixedArray()) { 2996 CHECK_NE(elements_to_trim, len); 2997 bytes_to_trim = elements_to_trim * kPointerSize; 2998 } else { 2999 DCHECK(object->IsFixedDoubleArray()); 3000 CHECK_NE(elements_to_trim, len); 3001 bytes_to_trim = elements_to_trim * kDoubleSize; 3002 } 3003 3004 CreateFillerForArray<FixedArrayBase>(object, elements_to_trim, bytes_to_trim); 3005 } 3006 3007 void Heap::RightTrimWeakFixedArray(WeakFixedArray* object, 3008 int elements_to_trim) { 3009 // This function is safe to use only at the end of the mark compact 3010 // collection: When marking, we record the weak slots, and shrinking 3011 // invalidates them. 3012 DCHECK_EQ(gc_state(), MARK_COMPACT); 3013 CreateFillerForArray<WeakFixedArray>(object, elements_to_trim, 3014 elements_to_trim * kPointerSize); 3015 } 3016 3017 template <typename T> 3018 void Heap::CreateFillerForArray(T* object, int elements_to_trim, 3019 int bytes_to_trim) { 3020 DCHECK(object->IsFixedArrayBase() || object->IsByteArray() || 3021 object->IsWeakFixedArray()); 3022 3023 // For now this trick is only applied to objects in new and paged space. 3024 DCHECK(object->map() != ReadOnlyRoots(this).fixed_cow_array_map()); 3025 3026 if (bytes_to_trim == 0) { 3027 DCHECK_EQ(elements_to_trim, 0); 3028 // No need to create filler and update live bytes counters. 3029 return; 3030 } 3031 3032 // Calculate location of new array end. 3033 int old_size = object->Size(); 3034 Address old_end = object->address() + old_size; 3035 Address new_end = old_end - bytes_to_trim; 3036 3037 // Register the array as an object with invalidated old-to-old slots. We 3038 // cannot use NotifyObjectLayoutChange as it would mark the array black, 3039 // which is not safe for left-trimming because left-trimming re-pushes 3040 // only grey arrays onto the marking worklist. 3041 if (incremental_marking()->IsCompacting() && 3042 MayContainRecordedSlots(object)) { 3043 // Ensure that the object survives because the InvalidatedSlotsFilter will 3044 // compute its size from its map during pointers updating phase. 3045 incremental_marking()->WhiteToGreyAndPush(object); 3046 MemoryChunk::FromHeapObject(object)->RegisterObjectWithInvalidatedSlots( 3047 object, old_size); 3048 } 3049 3050 // Technically in new space this write might be omitted (except for 3051 // debug mode which iterates through the heap), but to play safer 3052 // we still do it. 3053 // We do not create a filler for objects in large object space. 3054 // TODO(hpayer): We should shrink the large object page if the size 3055 // of the object changed significantly. 3056 if (!lo_space()->Contains(object)) { 3057 HeapObject* filler = 3058 CreateFillerObjectAt(new_end, bytes_to_trim, ClearRecordedSlots::kYes); 3059 DCHECK_NOT_NULL(filler); 3060 // Clear the mark bits of the black area that belongs now to the filler. 3061 // This is an optimization. The sweeper will release black fillers anyway. 3062 if (incremental_marking()->black_allocation() && 3063 incremental_marking()->marking_state()->IsBlackOrGrey(filler)) { 3064 Page* page = Page::FromAddress(new_end); 3065 incremental_marking()->marking_state()->bitmap(page)->ClearRange( 3066 page->AddressToMarkbitIndex(new_end), 3067 page->AddressToMarkbitIndex(new_end + bytes_to_trim)); 3068 } 3069 } 3070 3071 // Initialize header of the trimmed array. We are storing the new length 3072 // using release store after creating a filler for the left-over space to 3073 // avoid races with the sweeper thread. 3074 object->synchronized_set_length(object->length() - elements_to_trim); 3075 3076 // Notify the heap object allocation tracker of change in object layout. The 3077 // array may not be moved during GC, and size has to be adjusted nevertheless. 3078 for (auto& tracker : allocation_trackers_) { 3079 tracker->UpdateObjectSizeEvent(object->address(), object->Size()); 3080 } 3081 } 3082 3083 void Heap::MakeHeapIterable() { 3084 mark_compact_collector()->EnsureSweepingCompleted(); 3085 } 3086 3087 3088 static double ComputeMutatorUtilization(double mutator_speed, double gc_speed) { 3089 const double kMinMutatorUtilization = 0.0; 3090 const double kConservativeGcSpeedInBytesPerMillisecond = 200000; 3091 if (mutator_speed == 0) return kMinMutatorUtilization; 3092 if (gc_speed == 0) gc_speed = kConservativeGcSpeedInBytesPerMillisecond; 3093 // Derivation: 3094 // mutator_utilization = mutator_time / (mutator_time + gc_time) 3095 // mutator_time = 1 / mutator_speed 3096 // gc_time = 1 / gc_speed 3097 // mutator_utilization = (1 / mutator_speed) / 3098 // (1 / mutator_speed + 1 / gc_speed) 3099 // mutator_utilization = gc_speed / (mutator_speed + gc_speed) 3100 return gc_speed / (mutator_speed + gc_speed); 3101 } 3102 3103 3104 double Heap::YoungGenerationMutatorUtilization() { 3105 double mutator_speed = static_cast<double>( 3106 tracer()->NewSpaceAllocationThroughputInBytesPerMillisecond()); 3107 double gc_speed = 3108 tracer()->ScavengeSpeedInBytesPerMillisecond(kForSurvivedObjects); 3109 double result = ComputeMutatorUtilization(mutator_speed, gc_speed); 3110 if (FLAG_trace_mutator_utilization) { 3111 isolate()->PrintWithTimestamp( 3112 "Young generation mutator utilization = %.3f (" 3113 "mutator_speed=%.f, gc_speed=%.f)\n", 3114 result, mutator_speed, gc_speed); 3115 } 3116 return result; 3117 } 3118 3119 3120 double Heap::OldGenerationMutatorUtilization() { 3121 double mutator_speed = static_cast<double>( 3122 tracer()->OldGenerationAllocationThroughputInBytesPerMillisecond()); 3123 double gc_speed = static_cast<double>( 3124 tracer()->CombinedMarkCompactSpeedInBytesPerMillisecond()); 3125 double result = ComputeMutatorUtilization(mutator_speed, gc_speed); 3126 if (FLAG_trace_mutator_utilization) { 3127 isolate()->PrintWithTimestamp( 3128 "Old generation mutator utilization = %.3f (" 3129 "mutator_speed=%.f, gc_speed=%.f)\n", 3130 result, mutator_speed, gc_speed); 3131 } 3132 return result; 3133 } 3134 3135 3136 bool Heap::HasLowYoungGenerationAllocationRate() { 3137 const double high_mutator_utilization = 0.993; 3138 return YoungGenerationMutatorUtilization() > high_mutator_utilization; 3139 } 3140 3141 3142 bool Heap::HasLowOldGenerationAllocationRate() { 3143 const double high_mutator_utilization = 0.993; 3144 return OldGenerationMutatorUtilization() > high_mutator_utilization; 3145 } 3146 3147 3148 bool Heap::HasLowAllocationRate() { 3149 return HasLowYoungGenerationAllocationRate() && 3150 HasLowOldGenerationAllocationRate(); 3151 } 3152 3153 bool Heap::IsIneffectiveMarkCompact(size_t old_generation_size, 3154 double mutator_utilization) { 3155 const double kHighHeapPercentage = 0.8; 3156 const double kLowMutatorUtilization = 0.4; 3157 return old_generation_size >= 3158 kHighHeapPercentage * max_old_generation_size_ && 3159 mutator_utilization < kLowMutatorUtilization; 3160 } 3161 3162 void Heap::CheckIneffectiveMarkCompact(size_t old_generation_size, 3163 double mutator_utilization) { 3164 const int kMaxConsecutiveIneffectiveMarkCompacts = 4; 3165 if (!FLAG_detect_ineffective_gcs_near_heap_limit) return; 3166 if (!IsIneffectiveMarkCompact(old_generation_size, mutator_utilization)) { 3167 consecutive_ineffective_mark_compacts_ = 0; 3168 return; 3169 } 3170 ++consecutive_ineffective_mark_compacts_; 3171 if (consecutive_ineffective_mark_compacts_ == 3172 kMaxConsecutiveIneffectiveMarkCompacts) { 3173 if (InvokeNearHeapLimitCallback()) { 3174 // The callback increased the heap limit. 3175 consecutive_ineffective_mark_compacts_ = 0; 3176 return; 3177 } 3178 FatalProcessOutOfMemory("Ineffective mark-compacts near heap limit"); 3179 } 3180 } 3181 3182 bool Heap::HasHighFragmentation() { 3183 size_t used = OldGenerationSizeOfObjects(); 3184 size_t committed = CommittedOldGenerationMemory(); 3185 return HasHighFragmentation(used, committed); 3186 } 3187 3188 bool Heap::HasHighFragmentation(size_t used, size_t committed) { 3189 const size_t kSlack = 16 * MB; 3190 // Fragmentation is high if committed > 2 * used + kSlack. 3191 // Rewrite the exression to avoid overflow. 3192 DCHECK_GE(committed, used); 3193 return committed - used > used + kSlack; 3194 } 3195 3196 bool Heap::ShouldOptimizeForMemoryUsage() { 3197 const size_t kOldGenerationSlack = max_old_generation_size_ / 8; 3198 return FLAG_optimize_for_size || isolate()->IsIsolateInBackground() || 3199 isolate()->IsMemorySavingsModeActive() || HighMemoryPressure() || 3200 !CanExpandOldGeneration(kOldGenerationSlack); 3201 } 3202 3203 void Heap::ActivateMemoryReducerIfNeeded() { 3204 // Activate memory reducer when switching to background if 3205 // - there was no mark compact since the start. 3206 // - the committed memory can be potentially reduced. 3207 // 2 pages for the old, code, and map space + 1 page for new space. 3208 const int kMinCommittedMemory = 7 * Page::kPageSize; 3209 if (ms_count_ == 0 && CommittedMemory() > kMinCommittedMemory && 3210 isolate()->IsIsolateInBackground()) { 3211 MemoryReducer::Event event; 3212 event.type = MemoryReducer::kPossibleGarbage; 3213 event.time_ms = MonotonicallyIncreasingTimeInMs(); 3214 memory_reducer_->NotifyPossibleGarbage(event); 3215 } 3216 } 3217 3218 void Heap::ReduceNewSpaceSize() { 3219 // TODO(ulan): Unify this constant with the similar constant in 3220 // GCIdleTimeHandler once the change is merged to 4.5. 3221 static const size_t kLowAllocationThroughput = 1000; 3222 const double allocation_throughput = 3223 tracer()->CurrentAllocationThroughputInBytesPerMillisecond(); 3224 3225 if (FLAG_predictable) return; 3226 3227 if (ShouldReduceMemory() || 3228 ((allocation_throughput != 0) && 3229 (allocation_throughput < kLowAllocationThroughput))) { 3230 new_space_->Shrink(); 3231 UncommitFromSpace(); 3232 } 3233 } 3234 3235 void Heap::FinalizeIncrementalMarkingIfComplete( 3236 GarbageCollectionReason gc_reason) { 3237 if (incremental_marking()->IsMarking() && 3238 (incremental_marking()->IsReadyToOverApproximateWeakClosure() || 3239 (!incremental_marking()->finalize_marking_completed() && 3240 mark_compact_collector()->marking_worklist()->IsEmpty() && 3241 local_embedder_heap_tracer()->ShouldFinalizeIncrementalMarking()))) { 3242 FinalizeIncrementalMarkingIncrementally(gc_reason); 3243 } else if (incremental_marking()->IsComplete() || 3244 (mark_compact_collector()->marking_worklist()->IsEmpty() && 3245 local_embedder_heap_tracer() 3246 ->ShouldFinalizeIncrementalMarking())) { 3247 CollectAllGarbage(current_gc_flags_, gc_reason, current_gc_callback_flags_); 3248 } 3249 } 3250 3251 void Heap::FinalizeIncrementalMarkingAtomically( 3252 GarbageCollectionReason gc_reason) { 3253 DCHECK(!incremental_marking()->IsStopped()); 3254 CollectAllGarbage(current_gc_flags_, gc_reason, current_gc_callback_flags_); 3255 } 3256 3257 void Heap::FinalizeIncrementalMarkingIncrementally( 3258 GarbageCollectionReason gc_reason) { 3259 if (FLAG_trace_incremental_marking) { 3260 isolate()->PrintWithTimestamp( 3261 "[IncrementalMarking] (%s).\n", 3262 Heap::GarbageCollectionReasonToString(gc_reason)); 3263 } 3264 3265 HistogramTimerScope incremental_marking_scope( 3266 isolate()->counters()->gc_incremental_marking_finalize()); 3267 TRACE_EVENT0("v8", "V8.GCIncrementalMarkingFinalize"); 3268 TRACE_GC(tracer(), GCTracer::Scope::MC_INCREMENTAL_FINALIZE); 3269 3270 { 3271 GCCallbacksScope scope(this); 3272 if (scope.CheckReenter()) { 3273 AllowHeapAllocation allow_allocation; 3274 TRACE_GC(tracer(), GCTracer::Scope::MC_INCREMENTAL_EXTERNAL_PROLOGUE); 3275 VMState<EXTERNAL> state(isolate_); 3276 HandleScope handle_scope(isolate_); 3277 CallGCPrologueCallbacks(kGCTypeIncrementalMarking, kNoGCCallbackFlags); 3278 } 3279 } 3280 incremental_marking()->FinalizeIncrementally(); 3281 { 3282 GCCallbacksScope scope(this); 3283 if (scope.CheckReenter()) { 3284 AllowHeapAllocation allow_allocation; 3285 TRACE_GC(tracer(), GCTracer::Scope::MC_INCREMENTAL_EXTERNAL_EPILOGUE); 3286 VMState<EXTERNAL> state(isolate_); 3287 HandleScope handle_scope(isolate_); 3288 CallGCEpilogueCallbacks(kGCTypeIncrementalMarking, kNoGCCallbackFlags); 3289 } 3290 } 3291 } 3292 3293 void Heap::RegisterDeserializedObjectsForBlackAllocation( 3294 Reservation* reservations, const std::vector<HeapObject*>& large_objects, 3295 const std::vector<Address>& maps) { 3296 // TODO(ulan): pause black allocation during deserialization to avoid 3297 // iterating all these objects in one go. 3298 3299 if (!incremental_marking()->black_allocation()) return; 3300 3301 // Iterate black objects in old space, code space, map space, and large 3302 // object space for side effects. 3303 IncrementalMarking::MarkingState* marking_state = 3304 incremental_marking()->marking_state(); 3305 for (int i = OLD_SPACE; i < Serializer<>::kNumberOfSpaces; i++) { 3306 const Heap::Reservation& res = reservations[i]; 3307 for (auto& chunk : res) { 3308 Address addr = chunk.start; 3309 while (addr < chunk.end) { 3310 HeapObject* obj = HeapObject::FromAddress(addr); 3311 // Objects can have any color because incremental marking can 3312 // start in the middle of Heap::ReserveSpace(). 3313 if (marking_state->IsBlack(obj)) { 3314 incremental_marking()->ProcessBlackAllocatedObject(obj); 3315 } 3316 addr += obj->Size(); 3317 } 3318 } 3319 } 3320 // We potentially deserialized wrappers which require registering with the 3321 // embedder as the marker will not find them. 3322 local_embedder_heap_tracer()->RegisterWrappersWithRemoteTracer(); 3323 3324 // Large object space doesn't use reservations, so it needs custom handling. 3325 for (HeapObject* object : large_objects) { 3326 incremental_marking()->ProcessBlackAllocatedObject(object); 3327 } 3328 3329 // Map space doesn't use reservations, so it needs custom handling. 3330 for (Address addr : maps) { 3331 incremental_marking()->ProcessBlackAllocatedObject( 3332 HeapObject::FromAddress(addr)); 3333 } 3334 } 3335 3336 void Heap::NotifyObjectLayoutChange(HeapObject* object, int size, 3337 const DisallowHeapAllocation&) { 3338 if (incremental_marking()->IsMarking()) { 3339 incremental_marking()->MarkBlackAndPush(object); 3340 if (incremental_marking()->IsCompacting() && 3341 MayContainRecordedSlots(object)) { 3342 MemoryChunk::FromHeapObject(object)->RegisterObjectWithInvalidatedSlots( 3343 object, size); 3344 } 3345 } 3346 #ifdef VERIFY_HEAP 3347 if (FLAG_verify_heap) { 3348 DCHECK_NULL(pending_layout_change_object_); 3349 pending_layout_change_object_ = object; 3350 } 3351 #endif 3352 } 3353 3354 #ifdef VERIFY_HEAP 3355 // Helper class for collecting slot addresses. 3356 class SlotCollectingVisitor final : public ObjectVisitor { 3357 public: 3358 void VisitPointers(HeapObject* host, Object** start, Object** end) override { 3359 VisitPointers(host, reinterpret_cast<MaybeObject**>(start), 3360 reinterpret_cast<MaybeObject**>(end)); 3361 } 3362 void VisitPointers(HeapObject* host, MaybeObject** start, 3363 MaybeObject** end) final { 3364 for (MaybeObject** p = start; p < end; p++) { 3365 slots_.push_back(p); 3366 } 3367 } 3368 3369 int number_of_slots() { return static_cast<int>(slots_.size()); } 3370 3371 MaybeObject** slot(int i) { return slots_[i]; } 3372 3373 private: 3374 std::vector<MaybeObject**> slots_; 3375 }; 3376 3377 void Heap::VerifyObjectLayoutChange(HeapObject* object, Map* new_map) { 3378 if (!FLAG_verify_heap) return; 3379 3380 // Check that Heap::NotifyObjectLayout was called for object transitions 3381 // that are not safe for concurrent marking. 3382 // If you see this check triggering for a freshly allocated object, 3383 // use object->set_map_after_allocation() to initialize its map. 3384 if (pending_layout_change_object_ == nullptr) { 3385 if (object->IsJSObject()) { 3386 DCHECK(!object->map()->TransitionRequiresSynchronizationWithGC(new_map)); 3387 } else { 3388 // Check that the set of slots before and after the transition match. 3389 SlotCollectingVisitor old_visitor; 3390 object->IterateFast(&old_visitor); 3391 MapWord old_map_word = object->map_word(); 3392 // Temporarily set the new map to iterate new slots. 3393 object->set_map_word(MapWord::FromMap(new_map)); 3394 SlotCollectingVisitor new_visitor; 3395 object->IterateFast(&new_visitor); 3396 // Restore the old map. 3397 object->set_map_word(old_map_word); 3398 DCHECK_EQ(new_visitor.number_of_slots(), old_visitor.number_of_slots()); 3399 for (int i = 0; i < new_visitor.number_of_slots(); i++) { 3400 DCHECK_EQ(new_visitor.slot(i), old_visitor.slot(i)); 3401 } 3402 } 3403 } else { 3404 DCHECK_EQ(pending_layout_change_object_, object); 3405 pending_layout_change_object_ = nullptr; 3406 } 3407 } 3408 #endif 3409 3410 GCIdleTimeHeapState Heap::ComputeHeapState() { 3411 GCIdleTimeHeapState heap_state; 3412 heap_state.contexts_disposed = contexts_disposed_; 3413 heap_state.contexts_disposal_rate = 3414 tracer()->ContextDisposalRateInMilliseconds(); 3415 heap_state.size_of_objects = static_cast<size_t>(SizeOfObjects()); 3416 heap_state.incremental_marking_stopped = incremental_marking()->IsStopped(); 3417 return heap_state; 3418 } 3419 3420 3421 bool Heap::PerformIdleTimeAction(GCIdleTimeAction action, 3422 GCIdleTimeHeapState heap_state, 3423 double deadline_in_ms) { 3424 bool result = false; 3425 switch (action.type) { 3426 case DONE: 3427 result = true; 3428 break; 3429 case DO_INCREMENTAL_STEP: { 3430 const double remaining_idle_time_in_ms = 3431 incremental_marking()->AdvanceIncrementalMarking( 3432 deadline_in_ms, IncrementalMarking::NO_GC_VIA_STACK_GUARD, 3433 StepOrigin::kTask); 3434 if (remaining_idle_time_in_ms > 0.0) { 3435 FinalizeIncrementalMarkingIfComplete( 3436 GarbageCollectionReason::kFinalizeMarkingViaTask); 3437 } 3438 result = incremental_marking()->IsStopped(); 3439 break; 3440 } 3441 case DO_FULL_GC: { 3442 DCHECK_LT(0, contexts_disposed_); 3443 HistogramTimerScope scope(isolate_->counters()->gc_context()); 3444 TRACE_EVENT0("v8", "V8.GCContext"); 3445 CollectAllGarbage(kNoGCFlags, GarbageCollectionReason::kContextDisposal); 3446 break; 3447 } 3448 case DO_NOTHING: 3449 break; 3450 } 3451 3452 return result; 3453 } 3454 3455 void Heap::IdleNotificationEpilogue(GCIdleTimeAction action, 3456 GCIdleTimeHeapState heap_state, 3457 double start_ms, double deadline_in_ms) { 3458 double idle_time_in_ms = deadline_in_ms - start_ms; 3459 double current_time = MonotonicallyIncreasingTimeInMs(); 3460 last_idle_notification_time_ = current_time; 3461 double deadline_difference = deadline_in_ms - current_time; 3462 3463 contexts_disposed_ = 0; 3464 3465 if ((FLAG_trace_idle_notification && action.type > DO_NOTHING) || 3466 FLAG_trace_idle_notification_verbose) { 3467 isolate_->PrintWithTimestamp( 3468 "Idle notification: requested idle time %.2f ms, used idle time %.2f " 3469 "ms, deadline usage %.2f ms [", 3470 idle_time_in_ms, idle_time_in_ms - deadline_difference, 3471 deadline_difference); 3472 action.Print(); 3473 PrintF("]"); 3474 if (FLAG_trace_idle_notification_verbose) { 3475 PrintF("["); 3476 heap_state.Print(); 3477 PrintF("]"); 3478 } 3479 PrintF("\n"); 3480 } 3481 } 3482 3483 3484 double Heap::MonotonicallyIncreasingTimeInMs() { 3485 return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() * 3486 static_cast<double>(base::Time::kMillisecondsPerSecond); 3487 } 3488 3489 3490 bool Heap::IdleNotification(int idle_time_in_ms) { 3491 return IdleNotification( 3492 V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() + 3493 (static_cast<double>(idle_time_in_ms) / 3494 static_cast<double>(base::Time::kMillisecondsPerSecond))); 3495 } 3496 3497 3498 bool Heap::IdleNotification(double deadline_in_seconds) { 3499 CHECK(HasBeenSetUp()); 3500 double deadline_in_ms = 3501 deadline_in_seconds * 3502 static_cast<double>(base::Time::kMillisecondsPerSecond); 3503 HistogramTimerScope idle_notification_scope( 3504 isolate_->counters()->gc_idle_notification()); 3505 TRACE_EVENT0("v8", "V8.GCIdleNotification"); 3506 double start_ms = MonotonicallyIncreasingTimeInMs(); 3507 double idle_time_in_ms = deadline_in_ms - start_ms; 3508 3509 tracer()->SampleAllocation(start_ms, NewSpaceAllocationCounter(), 3510 OldGenerationAllocationCounter()); 3511 3512 GCIdleTimeHeapState heap_state = ComputeHeapState(); 3513 3514 GCIdleTimeAction action = 3515 gc_idle_time_handler_->Compute(idle_time_in_ms, heap_state); 3516 3517 bool result = PerformIdleTimeAction(action, heap_state, deadline_in_ms); 3518 3519 IdleNotificationEpilogue(action, heap_state, start_ms, deadline_in_ms); 3520 return result; 3521 } 3522 3523 3524 bool Heap::RecentIdleNotificationHappened() { 3525 return (last_idle_notification_time_ + 3526 GCIdleTimeHandler::kMaxScheduledIdleTime) > 3527 MonotonicallyIncreasingTimeInMs(); 3528 } 3529 3530 class MemoryPressureInterruptTask : public CancelableTask { 3531 public: 3532 explicit MemoryPressureInterruptTask(Heap* heap) 3533 : CancelableTask(heap->isolate()), heap_(heap) {} 3534 3535 virtual ~MemoryPressureInterruptTask() {} 3536 3537 private: 3538 // v8::internal::CancelableTask overrides. 3539 void RunInternal() override { heap_->CheckMemoryPressure(); } 3540 3541 Heap* heap_; 3542 DISALLOW_COPY_AND_ASSIGN(MemoryPressureInterruptTask); 3543 }; 3544 3545 void Heap::CheckMemoryPressure() { 3546 if (HighMemoryPressure()) { 3547 // The optimizing compiler may be unnecessarily holding on to memory. 3548 isolate()->AbortConcurrentOptimization(BlockingBehavior::kDontBlock); 3549 } 3550 MemoryPressureLevel memory_pressure_level = memory_pressure_level_; 3551 // Reset the memory pressure level to avoid recursive GCs triggered by 3552 // CheckMemoryPressure from AdjustAmountOfExternalMemory called by 3553 // the finalizers. 3554 memory_pressure_level_ = MemoryPressureLevel::kNone; 3555 if (memory_pressure_level == MemoryPressureLevel::kCritical) { 3556 CollectGarbageOnMemoryPressure(); 3557 } else if (memory_pressure_level == MemoryPressureLevel::kModerate) { 3558 if (FLAG_incremental_marking && incremental_marking()->IsStopped()) { 3559 StartIncrementalMarking(kReduceMemoryFootprintMask, 3560 GarbageCollectionReason::kMemoryPressure); 3561 } 3562 } 3563 if (memory_reducer_) { 3564 MemoryReducer::Event event; 3565 event.type = MemoryReducer::kPossibleGarbage; 3566 event.time_ms = MonotonicallyIncreasingTimeInMs(); 3567 memory_reducer_->NotifyPossibleGarbage(event); 3568 } 3569 } 3570 3571 void Heap::CollectGarbageOnMemoryPressure() { 3572 const int kGarbageThresholdInBytes = 8 * MB; 3573 const double kGarbageThresholdAsFractionOfTotalMemory = 0.1; 3574 // This constant is the maximum response time in RAIL performance model. 3575 const double kMaxMemoryPressurePauseMs = 100; 3576 3577 double start = MonotonicallyIncreasingTimeInMs(); 3578 CollectAllGarbage(kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, 3579 GarbageCollectionReason::kMemoryPressure, 3580 kGCCallbackFlagCollectAllAvailableGarbage); 3581 double end = MonotonicallyIncreasingTimeInMs(); 3582 3583 // Estimate how much memory we can free. 3584 int64_t potential_garbage = 3585 (CommittedMemory() - SizeOfObjects()) + external_memory_; 3586 // If we can potentially free large amount of memory, then start GC right 3587 // away instead of waiting for memory reducer. 3588 if (potential_garbage >= kGarbageThresholdInBytes && 3589 potential_garbage >= 3590 CommittedMemory() * kGarbageThresholdAsFractionOfTotalMemory) { 3591 // If we spent less than half of the time budget, then perform full GC 3592 // Otherwise, start incremental marking. 3593 if (end - start < kMaxMemoryPressurePauseMs / 2) { 3594 CollectAllGarbage( 3595 kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, 3596 GarbageCollectionReason::kMemoryPressure, 3597 kGCCallbackFlagCollectAllAvailableGarbage); 3598 } else { 3599 if (FLAG_incremental_marking && incremental_marking()->IsStopped()) { 3600 StartIncrementalMarking(kReduceMemoryFootprintMask, 3601 GarbageCollectionReason::kMemoryPressure); 3602 } 3603 } 3604 } 3605 } 3606 3607 void Heap::MemoryPressureNotification(MemoryPressureLevel level, 3608 bool is_isolate_locked) { 3609 MemoryPressureLevel previous = memory_pressure_level_; 3610 memory_pressure_level_ = level; 3611 if ((previous != MemoryPressureLevel::kCritical && 3612 level == MemoryPressureLevel::kCritical) || 3613 (previous == MemoryPressureLevel::kNone && 3614 level == MemoryPressureLevel::kModerate)) { 3615 if (is_isolate_locked) { 3616 CheckMemoryPressure(); 3617 } else { 3618 ExecutionAccess access(isolate()); 3619 isolate()->stack_guard()->RequestGC(); 3620 V8::GetCurrentPlatform()->CallOnForegroundThread( 3621 reinterpret_cast<v8::Isolate*>(isolate()), 3622 new MemoryPressureInterruptTask(this)); 3623 } 3624 } 3625 } 3626 3627 void Heap::AddNearHeapLimitCallback(v8::NearHeapLimitCallback callback, 3628 void* data) { 3629 const size_t kMaxCallbacks = 100; 3630 CHECK_LT(near_heap_limit_callbacks_.size(), kMaxCallbacks); 3631 for (auto callback_data : near_heap_limit_callbacks_) { 3632 CHECK_NE(callback_data.first, callback); 3633 } 3634 near_heap_limit_callbacks_.push_back(std::make_pair(callback, data)); 3635 } 3636 3637 void Heap::RemoveNearHeapLimitCallback(v8::NearHeapLimitCallback callback, 3638 size_t heap_limit) { 3639 for (size_t i = 0; i < near_heap_limit_callbacks_.size(); i++) { 3640 if (near_heap_limit_callbacks_[i].first == callback) { 3641 near_heap_limit_callbacks_.erase(near_heap_limit_callbacks_.begin() + i); 3642 if (heap_limit) { 3643 RestoreHeapLimit(heap_limit); 3644 } 3645 return; 3646 } 3647 } 3648 UNREACHABLE(); 3649 } 3650 3651 bool Heap::InvokeNearHeapLimitCallback() { 3652 if (near_heap_limit_callbacks_.size() > 0) { 3653 HandleScope scope(isolate()); 3654 v8::NearHeapLimitCallback callback = 3655 near_heap_limit_callbacks_.back().first; 3656 void* data = near_heap_limit_callbacks_.back().second; 3657 size_t heap_limit = callback(data, max_old_generation_size_, 3658 initial_max_old_generation_size_); 3659 if (heap_limit > max_old_generation_size_) { 3660 max_old_generation_size_ = heap_limit; 3661 return true; 3662 } 3663 } 3664 return false; 3665 } 3666 3667 void Heap::CollectCodeStatistics() { 3668 TRACE_EVENT0("v8", "Heap::CollectCodeStatistics"); 3669 CodeStatistics::ResetCodeAndMetadataStatistics(isolate()); 3670 // We do not look for code in new space, or map space. If code 3671 // somehow ends up in those spaces, we would miss it here. 3672 CodeStatistics::CollectCodeStatistics(code_space_, isolate()); 3673 CodeStatistics::CollectCodeStatistics(old_space_, isolate()); 3674 CodeStatistics::CollectCodeStatistics(lo_space_, isolate()); 3675 } 3676 3677 #ifdef DEBUG 3678 3679 void Heap::Print() { 3680 if (!HasBeenSetUp()) return; 3681 isolate()->PrintStack(stdout); 3682 3683 for (SpaceIterator it(this); it.has_next();) { 3684 it.next()->Print(); 3685 } 3686 } 3687 3688 3689 void Heap::ReportCodeStatistics(const char* title) { 3690 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title); 3691 CollectCodeStatistics(); 3692 CodeStatistics::ReportCodeStatistics(isolate()); 3693 } 3694 3695 #endif // DEBUG 3696 3697 const char* Heap::GarbageCollectionReasonToString( 3698 GarbageCollectionReason gc_reason) { 3699 switch (gc_reason) { 3700 case GarbageCollectionReason::kAllocationFailure: 3701 return "allocation failure"; 3702 case GarbageCollectionReason::kAllocationLimit: 3703 return "allocation limit"; 3704 case GarbageCollectionReason::kContextDisposal: 3705 return "context disposal"; 3706 case GarbageCollectionReason::kCountersExtension: 3707 return "counters extension"; 3708 case GarbageCollectionReason::kDebugger: 3709 return "debugger"; 3710 case GarbageCollectionReason::kDeserializer: 3711 return "deserialize"; 3712 case GarbageCollectionReason::kExternalMemoryPressure: 3713 return "external memory pressure"; 3714 case GarbageCollectionReason::kFinalizeMarkingViaStackGuard: 3715 return "finalize incremental marking via stack guard"; 3716 case GarbageCollectionReason::kFinalizeMarkingViaTask: 3717 return "finalize incremental marking via task"; 3718 case GarbageCollectionReason::kFullHashtable: 3719 return "full hash-table"; 3720 case GarbageCollectionReason::kHeapProfiler: 3721 return "heap profiler"; 3722 case GarbageCollectionReason::kIdleTask: 3723 return "idle task"; 3724 case GarbageCollectionReason::kLastResort: 3725 return "last resort"; 3726 case GarbageCollectionReason::kLowMemoryNotification: 3727 return "low memory notification"; 3728 case GarbageCollectionReason::kMakeHeapIterable: 3729 return "make heap iterable"; 3730 case GarbageCollectionReason::kMemoryPressure: 3731 return "memory pressure"; 3732 case GarbageCollectionReason::kMemoryReducer: 3733 return "memory reducer"; 3734 case GarbageCollectionReason::kRuntime: 3735 return "runtime"; 3736 case GarbageCollectionReason::kSamplingProfiler: 3737 return "sampling profiler"; 3738 case GarbageCollectionReason::kSnapshotCreator: 3739 return "snapshot creator"; 3740 case GarbageCollectionReason::kTesting: 3741 return "testing"; 3742 case GarbageCollectionReason::kExternalFinalize: 3743 return "external finalize"; 3744 case GarbageCollectionReason::kUnknown: 3745 return "unknown"; 3746 } 3747 UNREACHABLE(); 3748 } 3749 3750 bool Heap::Contains(HeapObject* value) { 3751 if (memory_allocator()->IsOutsideAllocatedSpace(value->address())) { 3752 return false; 3753 } 3754 return HasBeenSetUp() && 3755 (new_space_->ToSpaceContains(value) || old_space_->Contains(value) || 3756 code_space_->Contains(value) || map_space_->Contains(value) || 3757 lo_space_->Contains(value) || read_only_space_->Contains(value)); 3758 } 3759 3760 bool Heap::ContainsSlow(Address addr) { 3761 if (memory_allocator()->IsOutsideAllocatedSpace(addr)) { 3762 return false; 3763 } 3764 return HasBeenSetUp() && 3765 (new_space_->ToSpaceContainsSlow(addr) || 3766 old_space_->ContainsSlow(addr) || code_space_->ContainsSlow(addr) || 3767 map_space_->ContainsSlow(addr) || lo_space_->ContainsSlow(addr) || 3768 read_only_space_->Contains(addr)); 3769 } 3770 3771 bool Heap::InSpace(HeapObject* value, AllocationSpace space) { 3772 if (memory_allocator()->IsOutsideAllocatedSpace(value->address())) { 3773 return false; 3774 } 3775 if (!HasBeenSetUp()) return false; 3776 3777 switch (space) { 3778 case NEW_SPACE: 3779 return new_space_->ToSpaceContains(value); 3780 case OLD_SPACE: 3781 return old_space_->Contains(value); 3782 case CODE_SPACE: 3783 return code_space_->Contains(value); 3784 case MAP_SPACE: 3785 return map_space_->Contains(value); 3786 case LO_SPACE: 3787 return lo_space_->Contains(value); 3788 case NEW_LO_SPACE: 3789 return new_lo_space_->Contains(value); 3790 case RO_SPACE: 3791 return read_only_space_->Contains(value); 3792 } 3793 UNREACHABLE(); 3794 } 3795 3796 bool Heap::InSpaceSlow(Address addr, AllocationSpace space) { 3797 if (memory_allocator()->IsOutsideAllocatedSpace(addr)) { 3798 return false; 3799 } 3800 if (!HasBeenSetUp()) return false; 3801 3802 switch (space) { 3803 case NEW_SPACE: 3804 return new_space_->ToSpaceContainsSlow(addr); 3805 case OLD_SPACE: 3806 return old_space_->ContainsSlow(addr); 3807 case CODE_SPACE: 3808 return code_space_->ContainsSlow(addr); 3809 case MAP_SPACE: 3810 return map_space_->ContainsSlow(addr); 3811 case LO_SPACE: 3812 return lo_space_->ContainsSlow(addr); 3813 case NEW_LO_SPACE: 3814 return new_lo_space_->ContainsSlow(addr); 3815 case RO_SPACE: 3816 return read_only_space_->ContainsSlow(addr); 3817 } 3818 UNREACHABLE(); 3819 } 3820 3821 bool Heap::IsValidAllocationSpace(AllocationSpace space) { 3822 switch (space) { 3823 case NEW_SPACE: 3824 case OLD_SPACE: 3825 case CODE_SPACE: 3826 case MAP_SPACE: 3827 case LO_SPACE: 3828 case NEW_LO_SPACE: 3829 case RO_SPACE: 3830 return true; 3831 default: 3832 return false; 3833 } 3834 } 3835 3836 3837 bool Heap::RootIsImmortalImmovable(int root_index) { 3838 switch (root_index) { 3839 #define IMMORTAL_IMMOVABLE_ROOT(name) case Heap::k##name##RootIndex: 3840 IMMORTAL_IMMOVABLE_ROOT_LIST(IMMORTAL_IMMOVABLE_ROOT) 3841 #undef IMMORTAL_IMMOVABLE_ROOT 3842 #define INTERNALIZED_STRING(name, value) case Heap::k##name##RootIndex: 3843 INTERNALIZED_STRING_LIST(INTERNALIZED_STRING) 3844 #undef INTERNALIZED_STRING 3845 #define STRING_TYPE(NAME, size, name, Name) case Heap::k##Name##MapRootIndex: 3846 STRING_TYPE_LIST(STRING_TYPE) 3847 #undef STRING_TYPE 3848 return true; 3849 default: 3850 return false; 3851 } 3852 } 3853 3854 #ifdef VERIFY_HEAP 3855 class VerifyReadOnlyPointersVisitor : public VerifyPointersVisitor { 3856 public: 3857 explicit VerifyReadOnlyPointersVisitor(Heap* heap) 3858 : VerifyPointersVisitor(heap) {} 3859 3860 protected: 3861 void VerifyPointers(HeapObject* host, MaybeObject** start, 3862 MaybeObject** end) override { 3863 if (host != nullptr) { 3864 CHECK(heap_->InReadOnlySpace(host->map())); 3865 } 3866 VerifyPointersVisitor::VerifyPointers(host, start, end); 3867 3868 for (MaybeObject** current = start; current < end; current++) { 3869 HeapObject* object; 3870 if ((*current)->ToStrongOrWeakHeapObject(&object)) { 3871 CHECK(heap_->InReadOnlySpace(object)); 3872 } 3873 } 3874 } 3875 }; 3876 3877 void Heap::Verify() { 3878 CHECK(HasBeenSetUp()); 3879 HandleScope scope(isolate()); 3880 3881 // We have to wait here for the sweeper threads to have an iterable heap. 3882 mark_compact_collector()->EnsureSweepingCompleted(); 3883 3884 VerifyPointersVisitor visitor(this); 3885 IterateRoots(&visitor, VISIT_ONLY_STRONG); 3886 3887 VerifySmisVisitor smis_visitor; 3888 IterateSmiRoots(&smis_visitor); 3889 3890 new_space_->Verify(isolate()); 3891 3892 old_space_->Verify(isolate(), &visitor); 3893 map_space_->Verify(isolate(), &visitor); 3894 3895 VerifyPointersVisitor no_dirty_regions_visitor(this); 3896 code_space_->Verify(isolate(), &no_dirty_regions_visitor); 3897 3898 lo_space_->Verify(isolate()); 3899 3900 VerifyReadOnlyPointersVisitor read_only_visitor(this); 3901 read_only_space_->Verify(isolate(), &read_only_visitor); 3902 } 3903 3904 class SlotVerifyingVisitor : public ObjectVisitor { 3905 public: 3906 SlotVerifyingVisitor(std::set<Address>* untyped, 3907 std::set<std::pair<SlotType, Address> >* typed) 3908 : untyped_(untyped), typed_(typed) {} 3909 3910 virtual bool ShouldHaveBeenRecorded(HeapObject* host, 3911 MaybeObject* target) = 0; 3912 3913 void VisitPointers(HeapObject* host, Object** start, Object** end) override { 3914 #ifdef DEBUG 3915 for (Object** slot = start; slot < end; slot++) { 3916 DCHECK(!HasWeakHeapObjectTag(*slot)); 3917 } 3918 #endif // DEBUG 3919 VisitPointers(host, reinterpret_cast<MaybeObject**>(start), 3920 reinterpret_cast<MaybeObject**>(end)); 3921 } 3922 3923 void VisitPointers(HeapObject* host, MaybeObject** start, 3924 MaybeObject** end) final { 3925 for (MaybeObject** slot = start; slot < end; slot++) { 3926 if (ShouldHaveBeenRecorded(host, *slot)) { 3927 CHECK_GT(untyped_->count(reinterpret_cast<Address>(slot)), 0); 3928 } 3929 } 3930 } 3931 3932 void VisitCodeTarget(Code* host, RelocInfo* rinfo) override { 3933 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); 3934 if (ShouldHaveBeenRecorded(host, MaybeObject::FromObject(target))) { 3935 CHECK( 3936 InTypedSet(CODE_TARGET_SLOT, rinfo->pc()) || 3937 (rinfo->IsInConstantPool() && 3938 InTypedSet(CODE_ENTRY_SLOT, rinfo->constant_pool_entry_address()))); 3939 } 3940 } 3941 3942 void VisitEmbeddedPointer(Code* host, RelocInfo* rinfo) override { 3943 Object* target = rinfo->target_object(); 3944 if (ShouldHaveBeenRecorded(host, MaybeObject::FromObject(target))) { 3945 CHECK(InTypedSet(EMBEDDED_OBJECT_SLOT, rinfo->pc()) || 3946 (rinfo->IsInConstantPool() && 3947 InTypedSet(OBJECT_SLOT, rinfo->constant_pool_entry_address()))); 3948 } 3949 } 3950 3951 private: 3952 bool InTypedSet(SlotType type, Address slot) { 3953 return typed_->count(std::make_pair(type, slot)) > 0; 3954 } 3955 std::set<Address>* untyped_; 3956 std::set<std::pair<SlotType, Address> >* typed_; 3957 }; 3958 3959 class OldToNewSlotVerifyingVisitor : public SlotVerifyingVisitor { 3960 public: 3961 OldToNewSlotVerifyingVisitor(std::set<Address>* untyped, 3962 std::set<std::pair<SlotType, Address>>* typed) 3963 : SlotVerifyingVisitor(untyped, typed) {} 3964 3965 bool ShouldHaveBeenRecorded(HeapObject* host, MaybeObject* target) override { 3966 DCHECK_IMPLIES( 3967 target->IsStrongOrWeakHeapObject() && Heap::InNewSpace(target), 3968 Heap::InToSpace(target)); 3969 return target->IsStrongOrWeakHeapObject() && Heap::InNewSpace(target) && 3970 !Heap::InNewSpace(host); 3971 } 3972 }; 3973 3974 template <RememberedSetType direction> 3975 void CollectSlots(MemoryChunk* chunk, Address start, Address end, 3976 std::set<Address>* untyped, 3977 std::set<std::pair<SlotType, Address> >* typed) { 3978 RememberedSet<direction>::Iterate(chunk, 3979 [start, end, untyped](Address slot) { 3980 if (start <= slot && slot < end) { 3981 untyped->insert(slot); 3982 } 3983 return KEEP_SLOT; 3984 }, 3985 SlotSet::PREFREE_EMPTY_BUCKETS); 3986 RememberedSet<direction>::IterateTyped( 3987 chunk, [start, end, typed](SlotType type, Address host, Address slot) { 3988 if (start <= slot && slot < end) { 3989 typed->insert(std::make_pair(type, slot)); 3990 } 3991 return KEEP_SLOT; 3992 }); 3993 } 3994 3995 void Heap::VerifyRememberedSetFor(HeapObject* object) { 3996 MemoryChunk* chunk = MemoryChunk::FromAddress(object->address()); 3997 DCHECK_IMPLIES(chunk->mutex() == nullptr, InReadOnlySpace(object)); 3998 // In RO_SPACE chunk->mutex() may be nullptr, so just ignore it. 3999 base::LockGuard<base::Mutex, base::NullBehavior::kIgnoreIfNull> lock_guard( 4000 chunk->mutex()); 4001 Address start = object->address(); 4002 Address end = start + object->Size(); 4003 std::set<Address> old_to_new; 4004 std::set<std::pair<SlotType, Address> > typed_old_to_new; 4005 if (!InNewSpace(object)) { 4006 store_buffer()->MoveAllEntriesToRememberedSet(); 4007 CollectSlots<OLD_TO_NEW>(chunk, start, end, &old_to_new, &typed_old_to_new); 4008 OldToNewSlotVerifyingVisitor visitor(&old_to_new, &typed_old_to_new); 4009 object->IterateBody(&visitor); 4010 } 4011 // TODO(ulan): Add old to old slot set verification once all weak objects 4012 // have their own instance types and slots are recorded for all weal fields. 4013 } 4014 #endif 4015 4016 #ifdef DEBUG 4017 void Heap::VerifyCountersAfterSweeping() { 4018 PagedSpaces spaces(this); 4019 for (PagedSpace* space = spaces.next(); space != nullptr; 4020 space = spaces.next()) { 4021 space->VerifyCountersAfterSweeping(); 4022 } 4023 } 4024 4025 void Heap::VerifyCountersBeforeConcurrentSweeping() { 4026 PagedSpaces spaces(this); 4027 for (PagedSpace* space = spaces.next(); space != nullptr; 4028 space = spaces.next()) { 4029 space->VerifyCountersBeforeConcurrentSweeping(); 4030 } 4031 } 4032 #endif 4033 4034 void Heap::ZapFromSpace() { 4035 if (!new_space_->IsFromSpaceCommitted()) return; 4036 for (Page* page : PageRange(new_space_->from_space().first_page(), nullptr)) { 4037 memory_allocator()->ZapBlock(page->area_start(), 4038 page->HighWaterMark() - page->area_start(), 4039 ZapValue()); 4040 } 4041 } 4042 4043 void Heap::ZapCodeObject(Address start_address, int size_in_bytes) { 4044 #ifdef DEBUG 4045 for (int i = 0; i < size_in_bytes / kPointerSize; i++) { 4046 reinterpret_cast<Object**>(start_address)[i] = Smi::FromInt(kCodeZapValue); 4047 } 4048 #endif 4049 } 4050 4051 Code* Heap::builtin(int index) { 4052 DCHECK(Builtins::IsBuiltinId(index)); 4053 // Code::cast cannot be used here since we access builtins 4054 // during the marking phase of mark sweep. See IC::Clear. 4055 return reinterpret_cast<Code*>(builtins_[index]); 4056 } 4057 4058 Address Heap::builtin_address(int index) { 4059 DCHECK(Builtins::IsBuiltinId(index) || index == Builtins::builtin_count); 4060 return reinterpret_cast<Address>(&builtins_[index]); 4061 } 4062 4063 void Heap::set_builtin(int index, HeapObject* builtin) { 4064 DCHECK(Builtins::IsBuiltinId(index)); 4065 DCHECK(Internals::HasHeapObjectTag(builtin)); 4066 // The given builtin may be completely uninitialized thus we cannot check its 4067 // type here. 4068 builtins_[index] = builtin; 4069 } 4070 4071 void Heap::IterateRoots(RootVisitor* v, VisitMode mode) { 4072 IterateStrongRoots(v, mode); 4073 IterateWeakRoots(v, mode); 4074 } 4075 4076 void Heap::IterateWeakRoots(RootVisitor* v, VisitMode mode) { 4077 const bool isMinorGC = mode == VISIT_ALL_IN_SCAVENGE || 4078 mode == VISIT_ALL_IN_MINOR_MC_MARK || 4079 mode == VISIT_ALL_IN_MINOR_MC_UPDATE; 4080 v->VisitRootPointer( 4081 Root::kStringTable, nullptr, 4082 reinterpret_cast<Object**>(&roots_[kStringTableRootIndex])); 4083 v->Synchronize(VisitorSynchronization::kStringTable); 4084 if (!isMinorGC && mode != VISIT_ALL_IN_SWEEP_NEWSPACE && 4085 mode != VISIT_FOR_SERIALIZATION) { 4086 // Scavenge collections have special processing for this. 4087 // Do not visit for serialization, since the external string table will 4088 // be populated from scratch upon deserialization. 4089 external_string_table_.IterateAll(v); 4090 } 4091 v->Synchronize(VisitorSynchronization::kExternalStringsTable); 4092 } 4093 4094 void Heap::IterateSmiRoots(RootVisitor* v) { 4095 // Acquire execution access since we are going to read stack limit values. 4096 ExecutionAccess access(isolate()); 4097 v->VisitRootPointers(Root::kSmiRootList, nullptr, &roots_[kSmiRootsStart], 4098 &roots_[kRootListLength]); 4099 v->Synchronize(VisitorSynchronization::kSmiRootList); 4100 } 4101 4102 // We cannot avoid stale handles to left-trimmed objects, but can only make 4103 // sure all handles still needed are updated. Filter out a stale pointer 4104 // and clear the slot to allow post processing of handles (needed because 4105 // the sweeper might actually free the underlying page). 4106 class FixStaleLeftTrimmedHandlesVisitor : public RootVisitor { 4107 public: 4108 explicit FixStaleLeftTrimmedHandlesVisitor(Heap* heap) : heap_(heap) { 4109 USE(heap_); 4110 } 4111 4112 void VisitRootPointer(Root root, const char* description, 4113 Object** p) override { 4114 FixHandle(p); 4115 } 4116 4117 void VisitRootPointers(Root root, const char* description, Object** start, 4118 Object** end) override { 4119 for (Object** p = start; p < end; p++) FixHandle(p); 4120 } 4121 4122 private: 4123 inline void FixHandle(Object** p) { 4124 if (!(*p)->IsHeapObject()) return; 4125 HeapObject* current = reinterpret_cast<HeapObject*>(*p); 4126 const MapWord map_word = current->map_word(); 4127 if (!map_word.IsForwardingAddress() && current->IsFiller()) { 4128 #ifdef DEBUG 4129 // We need to find a FixedArrayBase map after walking the fillers. 4130 while (current->IsFiller()) { 4131 Address next = reinterpret_cast<Address>(current); 4132 if (current->map() == ReadOnlyRoots(heap_).one_pointer_filler_map()) { 4133 next += kPointerSize; 4134 } else if (current->map() == 4135 ReadOnlyRoots(heap_).two_pointer_filler_map()) { 4136 next += 2 * kPointerSize; 4137 } else { 4138 next += current->Size(); 4139 } 4140 current = reinterpret_cast<HeapObject*>(next); 4141 } 4142 DCHECK(current->IsFixedArrayBase()); 4143 #endif // DEBUG 4144 *p = nullptr; 4145 } 4146 } 4147 4148 Heap* heap_; 4149 }; 4150 4151 void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) { 4152 const bool isMinorGC = mode == VISIT_ALL_IN_SCAVENGE || 4153 mode == VISIT_ALL_IN_MINOR_MC_MARK || 4154 mode == VISIT_ALL_IN_MINOR_MC_UPDATE; 4155 v->VisitRootPointers(Root::kStrongRootList, nullptr, &roots_[0], 4156 &roots_[kStrongRootListLength]); 4157 v->Synchronize(VisitorSynchronization::kStrongRootList); 4158 4159 isolate_->bootstrapper()->Iterate(v); 4160 v->Synchronize(VisitorSynchronization::kBootstrapper); 4161 isolate_->Iterate(v); 4162 v->Synchronize(VisitorSynchronization::kTop); 4163 Relocatable::Iterate(isolate_, v); 4164 v->Synchronize(VisitorSynchronization::kRelocatable); 4165 isolate_->debug()->Iterate(v); 4166 v->Synchronize(VisitorSynchronization::kDebug); 4167 4168 isolate_->compilation_cache()->Iterate(v); 4169 v->Synchronize(VisitorSynchronization::kCompilationCache); 4170 4171 // Iterate over local handles in handle scopes. 4172 FixStaleLeftTrimmedHandlesVisitor left_trim_visitor(this); 4173 isolate_->handle_scope_implementer()->Iterate(&left_trim_visitor); 4174 isolate_->handle_scope_implementer()->Iterate(v); 4175 isolate_->IterateDeferredHandles(v); 4176 v->Synchronize(VisitorSynchronization::kHandleScope); 4177 4178 // Iterate over the builtin code objects and code stubs in the 4179 // heap. Note that it is not necessary to iterate over code objects 4180 // on scavenge collections. 4181 if (!isMinorGC) { 4182 IterateBuiltins(v); 4183 v->Synchronize(VisitorSynchronization::kBuiltins); 4184 isolate_->interpreter()->IterateDispatchTable(v); 4185 v->Synchronize(VisitorSynchronization::kDispatchTable); 4186 } 4187 4188 // Iterate over global handles. 4189 switch (mode) { 4190 case VISIT_FOR_SERIALIZATION: 4191 // Global handles are not iterated by the serializer. Values referenced by 4192 // global handles need to be added manually. 4193 break; 4194 case VISIT_ONLY_STRONG: 4195 isolate_->global_handles()->IterateStrongRoots(v); 4196 break; 4197 case VISIT_ALL_IN_SCAVENGE: 4198 isolate_->global_handles()->IterateNewSpaceStrongAndDependentRoots(v); 4199 break; 4200 case VISIT_ALL_IN_MINOR_MC_MARK: 4201 // Global handles are processed manually be the minor MC. 4202 break; 4203 case VISIT_ALL_IN_MINOR_MC_UPDATE: 4204 // Global handles are processed manually be the minor MC. 4205 break; 4206 case VISIT_ALL_IN_SWEEP_NEWSPACE: 4207 case VISIT_ALL: 4208 isolate_->global_handles()->IterateAllRoots(v); 4209 break; 4210 } 4211 v->Synchronize(VisitorSynchronization::kGlobalHandles); 4212 4213 // Iterate over eternal handles. Eternal handles are not iterated by the 4214 // serializer. Values referenced by eternal handles need to be added manually. 4215 if (mode != VISIT_FOR_SERIALIZATION) { 4216 if (isMinorGC) { 4217 isolate_->eternal_handles()->IterateNewSpaceRoots(v); 4218 } else { 4219 isolate_->eternal_handles()->IterateAllRoots(v); 4220 } 4221 } 4222 v->Synchronize(VisitorSynchronization::kEternalHandles); 4223 4224 // Iterate over pointers being held by inactive threads. 4225 isolate_->thread_manager()->Iterate(v); 4226 v->Synchronize(VisitorSynchronization::kThreadManager); 4227 4228 // Iterate over other strong roots (currently only identity maps). 4229 for (StrongRootsList* list = strong_roots_list_; list; list = list->next) { 4230 v->VisitRootPointers(Root::kStrongRoots, nullptr, list->start, list->end); 4231 } 4232 v->Synchronize(VisitorSynchronization::kStrongRoots); 4233 4234 // Iterate over the partial snapshot cache unless serializing. 4235 if (mode != VISIT_FOR_SERIALIZATION) { 4236 SerializerDeserializer::Iterate(isolate_, v); 4237 // We don't do a v->Synchronize call here because the serializer and the 4238 // deserializer are deliberately out of sync here. 4239 } 4240 } 4241 4242 void Heap::IterateWeakGlobalHandles(RootVisitor* v) { 4243 isolate_->global_handles()->IterateWeakRoots(v); 4244 } 4245 4246 void Heap::IterateBuiltins(RootVisitor* v) { 4247 for (int i = 0; i < Builtins::builtin_count; i++) { 4248 v->VisitRootPointer(Root::kBuiltins, Builtins::name(i), &builtins_[i]); 4249 } 4250 } 4251 4252 // TODO(1236194): Since the heap size is configurable on the command line 4253 // and through the API, we should gracefully handle the case that the heap 4254 // size is not big enough to fit all the initial objects. 4255 void Heap::ConfigureHeap(size_t max_semi_space_size_in_kb, 4256 size_t max_old_generation_size_in_mb, 4257 size_t code_range_size_in_mb) { 4258 // Overwrite default configuration. 4259 if (max_semi_space_size_in_kb != 0) { 4260 max_semi_space_size_ = 4261 RoundUp<Page::kPageSize>(max_semi_space_size_in_kb * KB); 4262 } 4263 if (max_old_generation_size_in_mb != 0) { 4264 max_old_generation_size_ = max_old_generation_size_in_mb * MB; 4265 } 4266 4267 // If max space size flags are specified overwrite the configuration. 4268 if (FLAG_max_semi_space_size > 0) { 4269 max_semi_space_size_ = static_cast<size_t>(FLAG_max_semi_space_size) * MB; 4270 } 4271 if (FLAG_max_old_space_size > 0) { 4272 max_old_generation_size_ = 4273 static_cast<size_t>(FLAG_max_old_space_size) * MB; 4274 } 4275 4276 if (Page::kPageSize > MB) { 4277 max_semi_space_size_ = RoundUp<Page::kPageSize>(max_semi_space_size_); 4278 max_old_generation_size_ = 4279 RoundUp<Page::kPageSize>(max_old_generation_size_); 4280 } 4281 4282 if (FLAG_stress_compaction) { 4283 // This will cause more frequent GCs when stressing. 4284 max_semi_space_size_ = MB; 4285 } 4286 4287 // The new space size must be a power of two to support single-bit testing 4288 // for containment. 4289 max_semi_space_size_ = static_cast<size_t>(base::bits::RoundUpToPowerOfTwo64( 4290 static_cast<uint64_t>(max_semi_space_size_))); 4291 4292 if (max_semi_space_size_ == kMaxSemiSpaceSizeInKB * KB) { 4293 // Start with at least 1*MB semi-space on machines with a lot of memory. 4294 initial_semispace_size_ = 4295 Max(initial_semispace_size_, static_cast<size_t>(1 * MB)); 4296 } 4297 4298 if (FLAG_min_semi_space_size > 0) { 4299 size_t initial_semispace_size = 4300 static_cast<size_t>(FLAG_min_semi_space_size) * MB; 4301 if (initial_semispace_size > max_semi_space_size_) { 4302 initial_semispace_size_ = max_semi_space_size_; 4303 if (FLAG_trace_gc) { 4304 PrintIsolate(isolate_, 4305 "Min semi-space size cannot be more than the maximum " 4306 "semi-space size of %" PRIuS " MB\n", 4307 max_semi_space_size_ / MB); 4308 } 4309 } else { 4310 initial_semispace_size_ = 4311 RoundUp<Page::kPageSize>(initial_semispace_size); 4312 } 4313 } 4314 4315 initial_semispace_size_ = Min(initial_semispace_size_, max_semi_space_size_); 4316 4317 if (FLAG_semi_space_growth_factor < 2) { 4318 FLAG_semi_space_growth_factor = 2; 4319 } 4320 4321 // The old generation is paged and needs at least one page for each space. 4322 int paged_space_count = 4323 LAST_GROWABLE_PAGED_SPACE - FIRST_GROWABLE_PAGED_SPACE + 1; 4324 initial_max_old_generation_size_ = max_old_generation_size_ = 4325 Max(static_cast<size_t>(paged_space_count * Page::kPageSize), 4326 max_old_generation_size_); 4327 4328 if (FLAG_initial_old_space_size > 0) { 4329 initial_old_generation_size_ = FLAG_initial_old_space_size * MB; 4330 } else { 4331 initial_old_generation_size_ = 4332 max_old_generation_size_ / kInitalOldGenerationLimitFactor; 4333 } 4334 old_generation_allocation_limit_ = initial_old_generation_size_; 4335 4336 // We rely on being able to allocate new arrays in paged spaces. 4337 DCHECK(kMaxRegularHeapObjectSize >= 4338 (JSArray::kSize + 4339 FixedArray::SizeFor(JSArray::kInitialMaxFastElementArray) + 4340 AllocationMemento::kSize)); 4341 4342 code_range_size_ = code_range_size_in_mb * MB; 4343 4344 configured_ = true; 4345 } 4346 4347 4348 void Heap::AddToRingBuffer(const char* string) { 4349 size_t first_part = 4350 Min(strlen(string), kTraceRingBufferSize - ring_buffer_end_); 4351 memcpy(trace_ring_buffer_ + ring_buffer_end_, string, first_part); 4352 ring_buffer_end_ += first_part; 4353 if (first_part < strlen(string)) { 4354 ring_buffer_full_ = true; 4355 size_t second_part = strlen(string) - first_part; 4356 memcpy(trace_ring_buffer_, string + first_part, second_part); 4357 ring_buffer_end_ = second_part; 4358 } 4359 } 4360 4361 4362 void Heap::GetFromRingBuffer(char* buffer) { 4363 size_t copied = 0; 4364 if (ring_buffer_full_) { 4365 copied = kTraceRingBufferSize - ring_buffer_end_; 4366 memcpy(buffer, trace_ring_buffer_ + ring_buffer_end_, copied); 4367 } 4368 memcpy(buffer + copied, trace_ring_buffer_, ring_buffer_end_); 4369 } 4370 4371 void Heap::ConfigureHeapDefault() { ConfigureHeap(0, 0, 0); } 4372 4373 void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { 4374 *stats->start_marker = HeapStats::kStartMarker; 4375 *stats->end_marker = HeapStats::kEndMarker; 4376 *stats->ro_space_size = read_only_space_->Size(); 4377 *stats->ro_space_capacity = read_only_space_->Capacity(); 4378 *stats->new_space_size = new_space_->Size(); 4379 *stats->new_space_capacity = new_space_->Capacity(); 4380 *stats->old_space_size = old_space_->SizeOfObjects(); 4381 *stats->old_space_capacity = old_space_->Capacity(); 4382 *stats->code_space_size = code_space_->SizeOfObjects(); 4383 *stats->code_space_capacity = code_space_->Capacity(); 4384 *stats->map_space_size = map_space_->SizeOfObjects(); 4385 *stats->map_space_capacity = map_space_->Capacity(); 4386 *stats->lo_space_size = lo_space_->Size(); 4387 isolate_->global_handles()->RecordStats(stats); 4388 *stats->memory_allocator_size = memory_allocator()->Size(); 4389 *stats->memory_allocator_capacity = 4390 memory_allocator()->Size() + memory_allocator()->Available(); 4391 *stats->os_error = base::OS::GetLastError(); 4392 *stats->malloced_memory = isolate_->allocator()->GetCurrentMemoryUsage(); 4393 *stats->malloced_peak_memory = isolate_->allocator()->GetMaxMemoryUsage(); 4394 if (take_snapshot) { 4395 HeapIterator iterator(this); 4396 for (HeapObject* obj = iterator.next(); obj != nullptr; 4397 obj = iterator.next()) { 4398 InstanceType type = obj->map()->instance_type(); 4399 DCHECK(0 <= type && type <= LAST_TYPE); 4400 stats->objects_per_type[type]++; 4401 stats->size_per_type[type] += obj->Size(); 4402 } 4403 } 4404 if (stats->last_few_messages != nullptr) 4405 GetFromRingBuffer(stats->last_few_messages); 4406 if (stats->js_stacktrace != nullptr) { 4407 FixedStringAllocator fixed(stats->js_stacktrace, kStacktraceBufferSize - 1); 4408 StringStream accumulator(&fixed, StringStream::kPrintObjectConcise); 4409 if (gc_state() == Heap::NOT_IN_GC) { 4410 isolate()->PrintStack(&accumulator, Isolate::kPrintStackVerbose); 4411 } else { 4412 accumulator.Add("Cannot get stack trace in GC."); 4413 } 4414 } 4415 } 4416 4417 size_t Heap::OldGenerationSizeOfObjects() { 4418 PagedSpaces spaces(this, PagedSpaces::SpacesSpecifier::kAllPagedSpaces); 4419 size_t total = 0; 4420 for (PagedSpace* space = spaces.next(); space != nullptr; 4421 space = spaces.next()) { 4422 total += space->SizeOfObjects(); 4423 } 4424 return total + lo_space_->SizeOfObjects(); 4425 } 4426 4427 uint64_t Heap::PromotedExternalMemorySize() { 4428 if (external_memory_ <= external_memory_at_last_mark_compact_) return 0; 4429 return static_cast<uint64_t>(external_memory_ - 4430 external_memory_at_last_mark_compact_); 4431 } 4432 4433 bool Heap::ShouldOptimizeForLoadTime() { 4434 return isolate()->rail_mode() == PERFORMANCE_LOAD && 4435 !AllocationLimitOvershotByLargeMargin() && 4436 MonotonicallyIncreasingTimeInMs() < 4437 isolate()->LoadStartTimeMs() + kMaxLoadTimeMs; 4438 } 4439 4440 // This predicate is called when an old generation space cannot allocated from 4441 // the free list and is about to add a new page. Returning false will cause a 4442 // major GC. It happens when the old generation allocation limit is reached and 4443 // - either we need to optimize for memory usage, 4444 // - or the incremental marking is not in progress and we cannot start it. 4445 bool Heap::ShouldExpandOldGenerationOnSlowAllocation() { 4446 if (always_allocate() || OldGenerationSpaceAvailable() > 0) return true; 4447 // We reached the old generation allocation limit. 4448 4449 if (ShouldOptimizeForMemoryUsage()) return false; 4450 4451 if (ShouldOptimizeForLoadTime()) return true; 4452 4453 if (incremental_marking()->NeedsFinalization()) { 4454 return !AllocationLimitOvershotByLargeMargin(); 4455 } 4456 4457 if (incremental_marking()->IsStopped() && 4458 IncrementalMarkingLimitReached() == IncrementalMarkingLimit::kNoLimit) { 4459 // We cannot start incremental marking. 4460 return false; 4461 } 4462 return true; 4463 } 4464 4465 Heap::HeapGrowingMode Heap::CurrentHeapGrowingMode() { 4466 if (ShouldReduceMemory() || FLAG_stress_compaction) { 4467 return Heap::HeapGrowingMode::kMinimal; 4468 } 4469 4470 if (ShouldOptimizeForMemoryUsage()) { 4471 return Heap::HeapGrowingMode::kConservative; 4472 } 4473 4474 if (memory_reducer()->ShouldGrowHeapSlowly()) { 4475 return Heap::HeapGrowingMode::kSlow; 4476 } 4477 4478 return Heap::HeapGrowingMode::kDefault; 4479 } 4480 4481 // This function returns either kNoLimit, kSoftLimit, or kHardLimit. 4482 // The kNoLimit means that either incremental marking is disabled or it is too 4483 // early to start incremental marking. 4484 // The kSoftLimit means that incremental marking should be started soon. 4485 // The kHardLimit means that incremental marking should be started immediately. 4486 Heap::IncrementalMarkingLimit Heap::IncrementalMarkingLimitReached() { 4487 // Code using an AlwaysAllocateScope assumes that the GC state does not 4488 // change; that implies that no marking steps must be performed. 4489 if (!incremental_marking()->CanBeActivated() || always_allocate()) { 4490 // Incremental marking is disabled or it is too early to start. 4491 return IncrementalMarkingLimit::kNoLimit; 4492 } 4493 if (FLAG_stress_incremental_marking) { 4494 return IncrementalMarkingLimit::kHardLimit; 4495 } 4496 if (OldGenerationSizeOfObjects() <= 4497 IncrementalMarking::kActivationThreshold) { 4498 // Incremental marking is disabled or it is too early to start. 4499 return IncrementalMarkingLimit::kNoLimit; 4500 } 4501 if ((FLAG_stress_compaction && (gc_count_ & 1) != 0) || 4502 HighMemoryPressure()) { 4503 // If there is high memory pressure or stress testing is enabled, then 4504 // start marking immediately. 4505 return IncrementalMarkingLimit::kHardLimit; 4506 } 4507 4508 if (FLAG_stress_marking > 0) { 4509 double gained_since_last_gc = 4510 PromotedSinceLastGC() + 4511 (external_memory_ - external_memory_at_last_mark_compact_); 4512 double size_before_gc = 4513 OldGenerationObjectsAndPromotedExternalMemorySize() - 4514 gained_since_last_gc; 4515 double bytes_to_limit = old_generation_allocation_limit_ - size_before_gc; 4516 if (bytes_to_limit > 0) { 4517 double current_percent = (gained_since_last_gc / bytes_to_limit) * 100.0; 4518 4519 if (FLAG_trace_stress_marking) { 4520 isolate()->PrintWithTimestamp( 4521 "[IncrementalMarking] %.2lf%% of the memory limit reached\n", 4522 current_percent); 4523 } 4524 4525 if (FLAG_fuzzer_gc_analysis) { 4526 // Skips values >=100% since they already trigger marking. 4527 if (current_percent < 100.0) { 4528 max_marking_limit_reached_ = 4529 std::max(max_marking_limit_reached_, current_percent); 4530 } 4531 } else if (static_cast<int>(current_percent) >= 4532 stress_marking_percentage_) { 4533 stress_marking_percentage_ = NextStressMarkingLimit(); 4534 return IncrementalMarkingLimit::kHardLimit; 4535 } 4536 } 4537 } 4538 4539 size_t old_generation_space_available = OldGenerationSpaceAvailable(); 4540 4541 if (old_generation_space_available > new_space_->Capacity()) { 4542 return IncrementalMarkingLimit::kNoLimit; 4543 } 4544 if (ShouldOptimizeForMemoryUsage()) { 4545 return IncrementalMarkingLimit::kHardLimit; 4546 } 4547 if (ShouldOptimizeForLoadTime()) { 4548 return IncrementalMarkingLimit::kNoLimit; 4549 } 4550 if (old_generation_space_available == 0) { 4551 return IncrementalMarkingLimit::kHardLimit; 4552 } 4553 return IncrementalMarkingLimit::kSoftLimit; 4554 } 4555 4556 void Heap::EnableInlineAllocation() { 4557 if (!inline_allocation_disabled_) return; 4558 inline_allocation_disabled_ = false; 4559 4560 // Update inline allocation limit for new space. 4561 new_space()->UpdateInlineAllocationLimit(0); 4562 } 4563 4564 4565 void Heap::DisableInlineAllocation() { 4566 if (inline_allocation_disabled_) return; 4567 inline_allocation_disabled_ = true; 4568 4569 // Update inline allocation limit for new space. 4570 new_space()->UpdateInlineAllocationLimit(0); 4571 4572 // Update inline allocation limit for old spaces. 4573 PagedSpaces spaces(this); 4574 CodeSpaceMemoryModificationScope modification_scope(this); 4575 for (PagedSpace* space = spaces.next(); space != nullptr; 4576 space = spaces.next()) { 4577 space->FreeLinearAllocationArea(); 4578 } 4579 } 4580 4581 HeapObject* Heap::EnsureImmovableCode(HeapObject* heap_object, 4582 int object_size) { 4583 // Code objects which should stay at a fixed address are allocated either 4584 // in the first page of code space, in large object space, or (during 4585 // snapshot creation) the containing page is marked as immovable. 4586 DCHECK(heap_object); 4587 DCHECK(code_space_->Contains(heap_object)); 4588 DCHECK_GE(object_size, 0); 4589 if (!Heap::IsImmovable(heap_object)) { 4590 if (isolate()->serializer_enabled() || 4591 code_space_->first_page()->Contains(heap_object->address())) { 4592 MemoryChunk::FromAddress(heap_object->address())->MarkNeverEvacuate(); 4593 } else { 4594 // Discard the first code allocation, which was on a page where it could 4595 // be moved. 4596 CreateFillerObjectAt(heap_object->address(), object_size, 4597 ClearRecordedSlots::kNo); 4598 heap_object = AllocateRawCodeInLargeObjectSpace(object_size); 4599 UnprotectAndRegisterMemoryChunk(heap_object); 4600 ZapCodeObject(heap_object->address(), object_size); 4601 OnAllocationEvent(heap_object, object_size); 4602 } 4603 } 4604 return heap_object; 4605 } 4606 4607 HeapObject* Heap::AllocateRawWithLightRetry(int size, AllocationSpace space, 4608 AllocationAlignment alignment) { 4609 HeapObject* result; 4610 AllocationResult alloc = AllocateRaw(size, space, alignment); 4611 if (alloc.To(&result)) { 4612 DCHECK(result != ReadOnlyRoots(this).exception()); 4613 return result; 4614 } 4615 // Two GCs before panicking. In newspace will almost always succeed. 4616 for (int i = 0; i < 2; i++) { 4617 CollectGarbage(alloc.RetrySpace(), 4618 GarbageCollectionReason::kAllocationFailure); 4619 alloc = AllocateRaw(size, space, alignment); 4620 if (alloc.To(&result)) { 4621 DCHECK(result != ReadOnlyRoots(this).exception()); 4622 return result; 4623 } 4624 } 4625 return nullptr; 4626 } 4627 4628 HeapObject* Heap::AllocateRawWithRetryOrFail(int size, AllocationSpace space, 4629 AllocationAlignment alignment) { 4630 AllocationResult alloc; 4631 HeapObject* result = AllocateRawWithLightRetry(size, space, alignment); 4632 if (result) return result; 4633 4634 isolate()->counters()->gc_last_resort_from_handles()->Increment(); 4635 CollectAllAvailableGarbage(GarbageCollectionReason::kLastResort); 4636 { 4637 AlwaysAllocateScope scope(isolate()); 4638 alloc = AllocateRaw(size, space, alignment); 4639 } 4640 if (alloc.To(&result)) { 4641 DCHECK(result != ReadOnlyRoots(this).exception()); 4642 return result; 4643 } 4644 // TODO(1181417): Fix this. 4645 FatalProcessOutOfMemory("CALL_AND_RETRY_LAST"); 4646 return nullptr; 4647 } 4648 4649 // TODO(jkummerow): Refactor this. AllocateRaw should take an "immovability" 4650 // parameter and just do what's necessary. 4651 HeapObject* Heap::AllocateRawCodeInLargeObjectSpace(int size) { 4652 AllocationResult alloc = lo_space()->AllocateRaw(size, EXECUTABLE); 4653 HeapObject* result; 4654 if (alloc.To(&result)) { 4655 DCHECK(result != ReadOnlyRoots(this).exception()); 4656 return result; 4657 } 4658 // Two GCs before panicking. 4659 for (int i = 0; i < 2; i++) { 4660 CollectGarbage(alloc.RetrySpace(), 4661 GarbageCollectionReason::kAllocationFailure); 4662 alloc = lo_space()->AllocateRaw(size, EXECUTABLE); 4663 if (alloc.To(&result)) { 4664 DCHECK(result != ReadOnlyRoots(this).exception()); 4665 return result; 4666 } 4667 } 4668 isolate()->counters()->gc_last_resort_from_handles()->Increment(); 4669 CollectAllAvailableGarbage(GarbageCollectionReason::kLastResort); 4670 { 4671 AlwaysAllocateScope scope(isolate()); 4672 alloc = lo_space()->AllocateRaw(size, EXECUTABLE); 4673 } 4674 if (alloc.To(&result)) { 4675 DCHECK(result != ReadOnlyRoots(this).exception()); 4676 return result; 4677 } 4678 // TODO(1181417): Fix this. 4679 FatalProcessOutOfMemory("CALL_AND_RETRY_LAST"); 4680 return nullptr; 4681 } 4682 4683 void Heap::SetUp() { 4684 #ifdef V8_ENABLE_ALLOCATION_TIMEOUT 4685 allocation_timeout_ = NextAllocationTimeout(); 4686 #endif 4687 4688 // Initialize heap spaces and initial maps and objects. 4689 // 4690 // If the heap is not yet configured (e.g. through the API), configure it. 4691 // Configuration is based on the flags new-space-size (really the semispace 4692 // size) and old-space-size if set or the initial values of semispace_size_ 4693 // and old_generation_size_ otherwise. 4694 if (!configured_) ConfigureHeapDefault(); 4695 4696 mmap_region_base_ = 4697 reinterpret_cast<uintptr_t>(v8::internal::GetRandomMmapAddr()) & 4698 ~kMmapRegionMask; 4699 4700 // Set up memory allocator. 4701 memory_allocator_ = 4702 new MemoryAllocator(isolate_, MaxReserved(), code_range_size_); 4703 4704 store_buffer_ = new StoreBuffer(this); 4705 4706 heap_controller_ = new HeapController(this); 4707 4708 mark_compact_collector_ = new MarkCompactCollector(this); 4709 incremental_marking_ = 4710 new IncrementalMarking(this, mark_compact_collector_->marking_worklist(), 4711 mark_compact_collector_->weak_objects()); 4712 4713 if (FLAG_concurrent_marking) { 4714 MarkCompactCollector::MarkingWorklist* marking_worklist = 4715 mark_compact_collector_->marking_worklist(); 4716 concurrent_marking_ = new ConcurrentMarking( 4717 this, marking_worklist->shared(), marking_worklist->bailout(), 4718 marking_worklist->on_hold(), mark_compact_collector_->weak_objects()); 4719 } else { 4720 concurrent_marking_ = 4721 new ConcurrentMarking(this, nullptr, nullptr, nullptr, nullptr); 4722 } 4723 4724 for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) { 4725 space_[i] = nullptr; 4726 } 4727 4728 space_[RO_SPACE] = read_only_space_ = new ReadOnlySpace(this); 4729 space_[NEW_SPACE] = new_space_ = 4730 new NewSpace(this, initial_semispace_size_, max_semi_space_size_); 4731 space_[OLD_SPACE] = old_space_ = new OldSpace(this); 4732 space_[CODE_SPACE] = code_space_ = new CodeSpace(this); 4733 space_[MAP_SPACE] = map_space_ = new MapSpace(this); 4734 space_[LO_SPACE] = lo_space_ = new LargeObjectSpace(this); 4735 space_[NEW_LO_SPACE] = new_lo_space_ = new NewLargeObjectSpace(this); 4736 4737 for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount); 4738 i++) { 4739 deferred_counters_[i] = 0; 4740 } 4741 4742 tracer_ = new GCTracer(this); 4743 #ifdef ENABLE_MINOR_MC 4744 minor_mark_compact_collector_ = new MinorMarkCompactCollector(this); 4745 #else 4746 minor_mark_compact_collector_ = nullptr; 4747 #endif // ENABLE_MINOR_MC 4748 array_buffer_collector_ = new ArrayBufferCollector(this); 4749 gc_idle_time_handler_ = new GCIdleTimeHandler(); 4750 memory_reducer_ = new MemoryReducer(this); 4751 if (V8_UNLIKELY(FLAG_gc_stats)) { 4752 live_object_stats_ = new ObjectStats(this); 4753 dead_object_stats_ = new ObjectStats(this); 4754 } 4755 scavenge_job_ = new ScavengeJob(); 4756 local_embedder_heap_tracer_ = new LocalEmbedderHeapTracer(isolate()); 4757 4758 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity())); 4759 LOG(isolate_, IntPtrTEvent("heap-available", Available())); 4760 4761 store_buffer()->SetUp(); 4762 4763 mark_compact_collector()->SetUp(); 4764 #ifdef ENABLE_MINOR_MC 4765 if (minor_mark_compact_collector() != nullptr) { 4766 minor_mark_compact_collector()->SetUp(); 4767 } 4768 #endif // ENABLE_MINOR_MC 4769 4770 idle_scavenge_observer_ = new IdleScavengeObserver( 4771 *this, ScavengeJob::kBytesAllocatedBeforeNextIdleTask); 4772 new_space()->AddAllocationObserver(idle_scavenge_observer_); 4773 4774 SetGetExternallyAllocatedMemoryInBytesCallback( 4775 DefaultGetExternallyAllocatedMemoryInBytesCallback); 4776 4777 if (FLAG_stress_marking > 0) { 4778 stress_marking_percentage_ = NextStressMarkingLimit(); 4779 stress_marking_observer_ = new StressMarkingObserver(*this); 4780 AddAllocationObserversToAllSpaces(stress_marking_observer_, 4781 stress_marking_observer_); 4782 } 4783 if (FLAG_stress_scavenge > 0) { 4784 stress_scavenge_observer_ = new StressScavengeObserver(*this); 4785 new_space()->AddAllocationObserver(stress_scavenge_observer_); 4786 } 4787 4788 write_protect_code_memory_ = FLAG_write_protect_code_memory; 4789 4790 external_reference_table_.Init(isolate_); 4791 } 4792 4793 void Heap::InitializeHashSeed() { 4794 uint64_t new_hash_seed; 4795 if (FLAG_hash_seed == 0) { 4796 int64_t rnd = isolate()->random_number_generator()->NextInt64(); 4797 new_hash_seed = static_cast<uint64_t>(rnd); 4798 } else { 4799 new_hash_seed = static_cast<uint64_t>(FLAG_hash_seed); 4800 } 4801 hash_seed()->copy_in(0, reinterpret_cast<byte*>(&new_hash_seed), kInt64Size); 4802 } 4803 4804 void Heap::SetStackLimits() { 4805 DCHECK_NOT_NULL(isolate_); 4806 DCHECK(isolate_ == isolate()); 4807 // On 64 bit machines, pointers are generally out of range of Smis. We write 4808 // something that looks like an out of range Smi to the GC. 4809 4810 // Set up the special root array entries containing the stack limits. 4811 // These are actually addresses, but the tag makes the GC ignore it. 4812 roots_[kStackLimitRootIndex] = reinterpret_cast<Object*>( 4813 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag); 4814 roots_[kRealStackLimitRootIndex] = reinterpret_cast<Object*>( 4815 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag); 4816 } 4817 4818 void Heap::ClearStackLimits() { 4819 roots_[kStackLimitRootIndex] = Smi::kZero; 4820 roots_[kRealStackLimitRootIndex] = Smi::kZero; 4821 } 4822 4823 int Heap::NextAllocationTimeout(int current_timeout) { 4824 if (FLAG_random_gc_interval > 0) { 4825 // If current timeout hasn't reached 0 the GC was caused by something 4826 // different than --stress-atomic-gc flag and we don't update the timeout. 4827 if (current_timeout <= 0) { 4828 return isolate()->fuzzer_rng()->NextInt(FLAG_random_gc_interval + 1); 4829 } else { 4830 return current_timeout; 4831 } 4832 } 4833 return FLAG_gc_interval; 4834 } 4835 4836 void Heap::PrintAllocationsHash() { 4837 uint32_t hash = StringHasher::GetHashCore(raw_allocations_hash_); 4838 PrintF("\n### Allocations = %u, hash = 0x%08x\n", allocations_count(), hash); 4839 } 4840 4841 void Heap::PrintMaxMarkingLimitReached() { 4842 PrintF("\n### Maximum marking limit reached = %.02lf\n", 4843 max_marking_limit_reached_); 4844 } 4845 4846 void Heap::PrintMaxNewSpaceSizeReached() { 4847 PrintF("\n### Maximum new space size reached = %.02lf\n", 4848 stress_scavenge_observer_->MaxNewSpaceSizeReached()); 4849 } 4850 4851 int Heap::NextStressMarkingLimit() { 4852 return isolate()->fuzzer_rng()->NextInt(FLAG_stress_marking + 1); 4853 } 4854 4855 void Heap::NotifyDeserializationComplete() { 4856 PagedSpaces spaces(this); 4857 for (PagedSpace* s = spaces.next(); s != nullptr; s = spaces.next()) { 4858 if (isolate()->snapshot_available()) s->ShrinkImmortalImmovablePages(); 4859 #ifdef DEBUG 4860 // All pages right after bootstrapping must be marked as never-evacuate. 4861 for (Page* p : *s) { 4862 DCHECK(p->NeverEvacuate()); 4863 } 4864 #endif // DEBUG 4865 } 4866 4867 read_only_space()->MarkAsReadOnly(); 4868 deserialization_complete_ = true; 4869 } 4870 4871 void Heap::SetEmbedderHeapTracer(EmbedderHeapTracer* tracer) { 4872 DCHECK_EQ(gc_state_, HeapState::NOT_IN_GC); 4873 local_embedder_heap_tracer()->SetRemoteTracer(tracer); 4874 } 4875 4876 void Heap::TracePossibleWrapper(JSObject* js_object) { 4877 DCHECK(js_object->IsApiWrapper()); 4878 if (js_object->GetEmbedderFieldCount() >= 2 && 4879 js_object->GetEmbedderField(0) && 4880 js_object->GetEmbedderField(0) != ReadOnlyRoots(this).undefined_value() && 4881 js_object->GetEmbedderField(1) != ReadOnlyRoots(this).undefined_value()) { 4882 DCHECK_EQ(0, 4883 reinterpret_cast<intptr_t>(js_object->GetEmbedderField(0)) % 2); 4884 local_embedder_heap_tracer()->AddWrapperToTrace(std::pair<void*, void*>( 4885 reinterpret_cast<void*>(js_object->GetEmbedderField(0)), 4886 reinterpret_cast<void*>(js_object->GetEmbedderField(1)))); 4887 } 4888 } 4889 4890 void Heap::RegisterExternallyReferencedObject(Object** object) { 4891 // The embedder is not aware of whether numbers are materialized as heap 4892 // objects are just passed around as Smis. 4893 if (!(*object)->IsHeapObject()) return; 4894 HeapObject* heap_object = HeapObject::cast(*object); 4895 DCHECK(Contains(heap_object)); 4896 if (FLAG_incremental_marking_wrappers && incremental_marking()->IsMarking()) { 4897 incremental_marking()->WhiteToGreyAndPush(heap_object); 4898 } else { 4899 DCHECK(mark_compact_collector()->in_use()); 4900 mark_compact_collector()->MarkExternallyReferencedObject(heap_object); 4901 } 4902 } 4903 4904 void Heap::StartTearDown() { SetGCState(TEAR_DOWN); } 4905 4906 void Heap::TearDown() { 4907 DCHECK_EQ(gc_state_, TEAR_DOWN); 4908 #ifdef VERIFY_HEAP 4909 if (FLAG_verify_heap) { 4910 Verify(); 4911 } 4912 #endif 4913 4914 UpdateMaximumCommitted(); 4915 4916 if (FLAG_verify_predictable || FLAG_fuzzer_gc_analysis) { 4917 PrintAllocationsHash(); 4918 } 4919 4920 if (FLAG_fuzzer_gc_analysis) { 4921 if (FLAG_stress_marking > 0) { 4922 PrintMaxMarkingLimitReached(); 4923 } 4924 if (FLAG_stress_scavenge > 0) { 4925 PrintMaxNewSpaceSizeReached(); 4926 } 4927 } 4928 4929 new_space()->RemoveAllocationObserver(idle_scavenge_observer_); 4930 delete idle_scavenge_observer_; 4931 idle_scavenge_observer_ = nullptr; 4932 4933 if (FLAG_stress_marking > 0) { 4934 RemoveAllocationObserversFromAllSpaces(stress_marking_observer_, 4935 stress_marking_observer_); 4936 delete stress_marking_observer_; 4937 stress_marking_observer_ = nullptr; 4938 } 4939 if (FLAG_stress_scavenge > 0) { 4940 new_space()->RemoveAllocationObserver(stress_scavenge_observer_); 4941 delete stress_scavenge_observer_; 4942 stress_scavenge_observer_ = nullptr; 4943 } 4944 4945 if (heap_controller_ != nullptr) { 4946 delete heap_controller_; 4947 heap_controller_ = nullptr; 4948 } 4949 4950 if (mark_compact_collector_ != nullptr) { 4951 mark_compact_collector_->TearDown(); 4952 delete mark_compact_collector_; 4953 mark_compact_collector_ = nullptr; 4954 } 4955 4956 #ifdef ENABLE_MINOR_MC 4957 if (minor_mark_compact_collector_ != nullptr) { 4958 minor_mark_compact_collector_->TearDown(); 4959 delete minor_mark_compact_collector_; 4960 minor_mark_compact_collector_ = nullptr; 4961 } 4962 #endif // ENABLE_MINOR_MC 4963 4964 if (array_buffer_collector_ != nullptr) { 4965 delete array_buffer_collector_; 4966 array_buffer_collector_ = nullptr; 4967 } 4968 4969 delete incremental_marking_; 4970 incremental_marking_ = nullptr; 4971 4972 delete concurrent_marking_; 4973 concurrent_marking_ = nullptr; 4974 4975 delete gc_idle_time_handler_; 4976 gc_idle_time_handler_ = nullptr; 4977 4978 if (memory_reducer_ != nullptr) { 4979 memory_reducer_->TearDown(); 4980 delete memory_reducer_; 4981 memory_reducer_ = nullptr; 4982 } 4983 4984 if (live_object_stats_ != nullptr) { 4985 delete live_object_stats_; 4986 live_object_stats_ = nullptr; 4987 } 4988 4989 if (dead_object_stats_ != nullptr) { 4990 delete dead_object_stats_; 4991 dead_object_stats_ = nullptr; 4992 } 4993 4994 delete local_embedder_heap_tracer_; 4995 local_embedder_heap_tracer_ = nullptr; 4996 4997 delete scavenge_job_; 4998 scavenge_job_ = nullptr; 4999 5000 isolate_->global_handles()->TearDown(); 5001 5002 external_string_table_.TearDown(); 5003 5004 // Tear down all ArrayBuffers before tearing down the heap since their 5005 // byte_length may be a HeapNumber which is required for freeing the backing 5006 // store. 5007 ArrayBufferTracker::TearDown(this); 5008 5009 delete tracer_; 5010 tracer_ = nullptr; 5011 5012 for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) { 5013 delete space_[i]; 5014 space_[i] = nullptr; 5015 } 5016 5017 store_buffer()->TearDown(); 5018 5019 memory_allocator()->TearDown(); 5020 5021 StrongRootsList* next = nullptr; 5022 for (StrongRootsList* list = strong_roots_list_; list; list = next) { 5023 next = list->next; 5024 delete list; 5025 } 5026 strong_roots_list_ = nullptr; 5027 5028 delete store_buffer_; 5029 store_buffer_ = nullptr; 5030 5031 delete memory_allocator_; 5032 memory_allocator_ = nullptr; 5033 } 5034 5035 void Heap::AddGCPrologueCallback(v8::Isolate::GCCallbackWithData callback, 5036 GCType gc_type, void* data) { 5037 DCHECK_NOT_NULL(callback); 5038 DCHECK(gc_prologue_callbacks_.end() == 5039 std::find(gc_prologue_callbacks_.begin(), gc_prologue_callbacks_.end(), 5040 GCCallbackTuple(callback, gc_type, data))); 5041 gc_prologue_callbacks_.emplace_back(callback, gc_type, data); 5042 } 5043 5044 void Heap::RemoveGCPrologueCallback(v8::Isolate::GCCallbackWithData callback, 5045 void* data) { 5046 DCHECK_NOT_NULL(callback); 5047 for (size_t i = 0; i < gc_prologue_callbacks_.size(); i++) { 5048 if (gc_prologue_callbacks_[i].callback == callback && 5049 gc_prologue_callbacks_[i].data == data) { 5050 gc_prologue_callbacks_[i] = gc_prologue_callbacks_.back(); 5051 gc_prologue_callbacks_.pop_back(); 5052 return; 5053 } 5054 } 5055 UNREACHABLE(); 5056 } 5057 5058 void Heap::AddGCEpilogueCallback(v8::Isolate::GCCallbackWithData callback, 5059 GCType gc_type, void* data) { 5060 DCHECK_NOT_NULL(callback); 5061 DCHECK(gc_epilogue_callbacks_.end() == 5062 std::find(gc_epilogue_callbacks_.begin(), gc_epilogue_callbacks_.end(), 5063 GCCallbackTuple(callback, gc_type, data))); 5064 gc_epilogue_callbacks_.emplace_back(callback, gc_type, data); 5065 } 5066 5067 void Heap::RemoveGCEpilogueCallback(v8::Isolate::GCCallbackWithData callback, 5068 void* data) { 5069 DCHECK_NOT_NULL(callback); 5070 for (size_t i = 0; i < gc_epilogue_callbacks_.size(); i++) { 5071 if (gc_epilogue_callbacks_[i].callback == callback && 5072 gc_epilogue_callbacks_[i].data == data) { 5073 gc_epilogue_callbacks_[i] = gc_epilogue_callbacks_.back(); 5074 gc_epilogue_callbacks_.pop_back(); 5075 return; 5076 } 5077 } 5078 UNREACHABLE(); 5079 } 5080 5081 namespace { 5082 Handle<WeakArrayList> CompactWeakArrayList(Heap* heap, 5083 Handle<WeakArrayList> array, 5084 PretenureFlag pretenure) { 5085 if (array->length() == 0) { 5086 return array; 5087 } 5088 int new_length = array->CountLiveWeakReferences(); 5089 if (new_length == array->length()) { 5090 return array; 5091 } 5092 5093 Handle<WeakArrayList> new_array = WeakArrayList::EnsureSpace( 5094 heap->isolate(), 5095 handle(ReadOnlyRoots(heap).empty_weak_array_list(), heap->isolate()), 5096 new_length, pretenure); 5097 // Allocation might have caused GC and turned some of the elements into 5098 // cleared weak heap objects. Count the number of live references again and 5099 // fill in the new array. 5100 int copy_to = 0; 5101 for (int i = 0; i < array->length(); i++) { 5102 MaybeObject* element = array->Get(i); 5103 if (element->IsClearedWeakHeapObject()) continue; 5104 new_array->Set(copy_to++, element); 5105 } 5106 new_array->set_length(copy_to); 5107 return new_array; 5108 } 5109 5110 } // anonymous namespace 5111 5112 void Heap::CompactWeakArrayLists(PretenureFlag pretenure) { 5113 // Find known PrototypeUsers and compact them. 5114 std::vector<Handle<PrototypeInfo>> prototype_infos; 5115 { 5116 HeapIterator iterator(this); 5117 for (HeapObject* o = iterator.next(); o != nullptr; o = iterator.next()) { 5118 if (o->IsPrototypeInfo()) { 5119 PrototypeInfo* prototype_info = PrototypeInfo::cast(o); 5120 if (prototype_info->prototype_users()->IsWeakArrayList()) { 5121 prototype_infos.emplace_back(handle(prototype_info, isolate())); 5122 } 5123 } 5124 } 5125 } 5126 for (auto& prototype_info : prototype_infos) { 5127 Handle<WeakArrayList> array( 5128 WeakArrayList::cast(prototype_info->prototype_users()), isolate()); 5129 DCHECK_IMPLIES(pretenure == TENURED, 5130 InOldSpace(*array) || 5131 *array == ReadOnlyRoots(this).empty_weak_array_list()); 5132 WeakArrayList* new_array = PrototypeUsers::Compact( 5133 array, this, JSObject::PrototypeRegistryCompactionCallback, pretenure); 5134 prototype_info->set_prototype_users(new_array); 5135 } 5136 5137 // Find known WeakArrayLists and compact them. 5138 Handle<WeakArrayList> scripts(script_list(), isolate()); 5139 DCHECK_IMPLIES(pretenure == TENURED, InOldSpace(*scripts)); 5140 scripts = CompactWeakArrayList(this, scripts, pretenure); 5141 set_script_list(*scripts); 5142 5143 Handle<WeakArrayList> no_script_list(noscript_shared_function_infos(), 5144 isolate()); 5145 DCHECK_IMPLIES(pretenure == TENURED, InOldSpace(*no_script_list)); 5146 no_script_list = CompactWeakArrayList(this, no_script_list, pretenure); 5147 set_noscript_shared_function_infos(*no_script_list); 5148 } 5149 5150 void Heap::AddRetainedMap(Handle<Map> map) { 5151 if (map->is_in_retained_map_list()) { 5152 return; 5153 } 5154 Handle<WeakArrayList> array(retained_maps(), isolate()); 5155 if (array->IsFull()) { 5156 CompactRetainedMaps(*array); 5157 } 5158 array = 5159 WeakArrayList::AddToEnd(isolate(), array, MaybeObjectHandle::Weak(map)); 5160 array = WeakArrayList::AddToEnd( 5161 isolate(), array, 5162 MaybeObjectHandle(Smi::FromInt(FLAG_retain_maps_for_n_gc), isolate())); 5163 if (*array != retained_maps()) { 5164 set_retained_maps(*array); 5165 } 5166 map->set_is_in_retained_map_list(true); 5167 } 5168 5169 void Heap::CompactRetainedMaps(WeakArrayList* retained_maps) { 5170 DCHECK_EQ(retained_maps, this->retained_maps()); 5171 int length = retained_maps->length(); 5172 int new_length = 0; 5173 int new_number_of_disposed_maps = 0; 5174 // This loop compacts the array by removing cleared weak cells. 5175 for (int i = 0; i < length; i += 2) { 5176 MaybeObject* maybe_object = retained_maps->Get(i); 5177 if (maybe_object->IsClearedWeakHeapObject()) { 5178 continue; 5179 } 5180 5181 DCHECK(maybe_object->IsWeakHeapObject()); 5182 5183 MaybeObject* age = retained_maps->Get(i + 1); 5184 DCHECK(age->IsSmi()); 5185 if (i != new_length) { 5186 retained_maps->Set(new_length, maybe_object); 5187 retained_maps->Set(new_length + 1, age); 5188 } 5189 if (i < number_of_disposed_maps_) { 5190 new_number_of_disposed_maps += 2; 5191 } 5192 new_length += 2; 5193 } 5194 number_of_disposed_maps_ = new_number_of_disposed_maps; 5195 HeapObject* undefined = ReadOnlyRoots(this).undefined_value(); 5196 for (int i = new_length; i < length; i++) { 5197 retained_maps->Set(i, HeapObjectReference::Strong(undefined)); 5198 } 5199 if (new_length != length) retained_maps->set_length(new_length); 5200 } 5201 5202 void Heap::FatalProcessOutOfMemory(const char* location) { 5203 v8::internal::V8::FatalProcessOutOfMemory(isolate(), location, true); 5204 } 5205 5206 #ifdef DEBUG 5207 5208 class PrintHandleVisitor : public RootVisitor { 5209 public: 5210 void VisitRootPointers(Root root, const char* description, Object** start, 5211 Object** end) override { 5212 for (Object** p = start; p < end; p++) 5213 PrintF(" handle %p to %p\n", reinterpret_cast<void*>(p), 5214 reinterpret_cast<void*>(*p)); 5215 } 5216 }; 5217 5218 5219 void Heap::PrintHandles() { 5220 PrintF("Handles:\n"); 5221 PrintHandleVisitor v; 5222 isolate_->handle_scope_implementer()->Iterate(&v); 5223 } 5224 5225 #endif 5226 5227 class CheckHandleCountVisitor : public RootVisitor { 5228 public: 5229 CheckHandleCountVisitor() : handle_count_(0) {} 5230 ~CheckHandleCountVisitor() override { 5231 CHECK_GT(HandleScope::kCheckHandleThreshold, handle_count_); 5232 } 5233 void VisitRootPointers(Root root, const char* description, Object** start, 5234 Object** end) override { 5235 handle_count_ += end - start; 5236 } 5237 5238 private: 5239 ptrdiff_t handle_count_; 5240 }; 5241 5242 5243 void Heap::CheckHandleCount() { 5244 CheckHandleCountVisitor v; 5245 isolate_->handle_scope_implementer()->Iterate(&v); 5246 } 5247 5248 Address* Heap::store_buffer_top_address() { 5249 return store_buffer()->top_address(); 5250 } 5251 5252 // static 5253 intptr_t Heap::store_buffer_mask_constant() { 5254 return StoreBuffer::kStoreBufferMask; 5255 } 5256 5257 // static 5258 Address Heap::store_buffer_overflow_function_address() { 5259 return FUNCTION_ADDR(StoreBuffer::StoreBufferOverflow); 5260 } 5261 5262 void Heap::ClearRecordedSlot(HeapObject* object, Object** slot) { 5263 Address slot_addr = reinterpret_cast<Address>(slot); 5264 Page* page = Page::FromAddress(slot_addr); 5265 if (!page->InNewSpace()) { 5266 DCHECK_EQ(page->owner()->identity(), OLD_SPACE); 5267 store_buffer()->DeleteEntry(slot_addr); 5268 } 5269 } 5270 5271 bool Heap::HasRecordedSlot(HeapObject* object, Object** slot) { 5272 if (InNewSpace(object)) { 5273 return false; 5274 } 5275 Address slot_addr = reinterpret_cast<Address>(slot); 5276 Page* page = Page::FromAddress(slot_addr); 5277 DCHECK_EQ(page->owner()->identity(), OLD_SPACE); 5278 store_buffer()->MoveAllEntriesToRememberedSet(); 5279 return RememberedSet<OLD_TO_NEW>::Contains(page, slot_addr) || 5280 RememberedSet<OLD_TO_OLD>::Contains(page, slot_addr); 5281 } 5282 5283 void Heap::ClearRecordedSlotRange(Address start, Address end) { 5284 Page* page = Page::FromAddress(start); 5285 if (!page->InNewSpace()) { 5286 DCHECK_EQ(page->owner()->identity(), OLD_SPACE); 5287 store_buffer()->DeleteEntry(start, end); 5288 } 5289 } 5290 5291 PagedSpace* PagedSpaces::next() { 5292 switch (counter_++) { 5293 case RO_SPACE: 5294 // skip NEW_SPACE 5295 counter_++; 5296 return heap_->read_only_space(); 5297 case OLD_SPACE: 5298 return heap_->old_space(); 5299 case CODE_SPACE: 5300 return heap_->code_space(); 5301 case MAP_SPACE: 5302 return heap_->map_space(); 5303 default: 5304 return nullptr; 5305 } 5306 } 5307 5308 SpaceIterator::SpaceIterator(Heap* heap) 5309 : heap_(heap), current_space_(FIRST_SPACE - 1) {} 5310 5311 SpaceIterator::~SpaceIterator() { 5312 } 5313 5314 5315 bool SpaceIterator::has_next() { 5316 // Iterate until no more spaces. 5317 return current_space_ != LAST_SPACE; 5318 } 5319 5320 Space* SpaceIterator::next() { 5321 DCHECK(has_next()); 5322 return heap_->space(++current_space_); 5323 } 5324 5325 5326 class HeapObjectsFilter { 5327 public: 5328 virtual ~HeapObjectsFilter() {} 5329 virtual bool SkipObject(HeapObject* object) = 0; 5330 }; 5331 5332 5333 class UnreachableObjectsFilter : public HeapObjectsFilter { 5334 public: 5335 explicit UnreachableObjectsFilter(Heap* heap) : heap_(heap) { 5336 MarkReachableObjects(); 5337 } 5338 5339 ~UnreachableObjectsFilter() { 5340 for (auto it : reachable_) { 5341 delete it.second; 5342 it.second = nullptr; 5343 } 5344 } 5345 5346 bool SkipObject(HeapObject* object) { 5347 if (object->IsFiller()) return true; 5348 MemoryChunk* chunk = MemoryChunk::FromAddress(object->address()); 5349 if (reachable_.count(chunk) == 0) return true; 5350 return reachable_[chunk]->count(object) == 0; 5351 } 5352 5353 private: 5354 bool MarkAsReachable(HeapObject* object) { 5355 MemoryChunk* chunk = MemoryChunk::FromAddress(object->address()); 5356 if (reachable_.count(chunk) == 0) { 5357 reachable_[chunk] = new std::unordered_set<HeapObject*>(); 5358 } 5359 if (reachable_[chunk]->count(object)) return false; 5360 reachable_[chunk]->insert(object); 5361 return true; 5362 } 5363 5364 class MarkingVisitor : public ObjectVisitor, public RootVisitor { 5365 public: 5366 explicit MarkingVisitor(UnreachableObjectsFilter* filter) 5367 : filter_(filter) {} 5368 5369 void VisitPointers(HeapObject* host, Object** start, 5370 Object** end) override { 5371 MarkPointers(reinterpret_cast<MaybeObject**>(start), 5372 reinterpret_cast<MaybeObject**>(end)); 5373 } 5374 5375 void VisitPointers(HeapObject* host, MaybeObject** start, 5376 MaybeObject** end) final { 5377 MarkPointers(start, end); 5378 } 5379 5380 void VisitRootPointers(Root root, const char* description, Object** start, 5381 Object** end) override { 5382 MarkPointers(reinterpret_cast<MaybeObject**>(start), 5383 reinterpret_cast<MaybeObject**>(end)); 5384 } 5385 5386 void TransitiveClosure() { 5387 while (!marking_stack_.empty()) { 5388 HeapObject* obj = marking_stack_.back(); 5389 marking_stack_.pop_back(); 5390 obj->Iterate(this); 5391 } 5392 } 5393 5394 private: 5395 void MarkPointers(MaybeObject** start, MaybeObject** end) { 5396 // Treat weak references as strong. 5397 for (MaybeObject** p = start; p < end; p++) { 5398 HeapObject* heap_object; 5399 if ((*p)->ToStrongOrWeakHeapObject(&heap_object)) { 5400 if (filter_->MarkAsReachable(heap_object)) { 5401 marking_stack_.push_back(heap_object); 5402 } 5403 } 5404 } 5405 } 5406 UnreachableObjectsFilter* filter_; 5407 std::vector<HeapObject*> marking_stack_; 5408 }; 5409 5410 friend class MarkingVisitor; 5411 5412 void MarkReachableObjects() { 5413 MarkingVisitor visitor(this); 5414 heap_->IterateRoots(&visitor, VISIT_ALL); 5415 visitor.TransitiveClosure(); 5416 } 5417 5418 Heap* heap_; 5419 DisallowHeapAllocation no_allocation_; 5420 std::unordered_map<MemoryChunk*, std::unordered_set<HeapObject*>*> reachable_; 5421 }; 5422 5423 HeapIterator::HeapIterator(Heap* heap, 5424 HeapIterator::HeapObjectsFiltering filtering) 5425 : no_heap_allocation_(), 5426 heap_(heap), 5427 filtering_(filtering), 5428 filter_(nullptr), 5429 space_iterator_(nullptr), 5430 object_iterator_(nullptr) { 5431 heap_->MakeHeapIterable(); 5432 heap_->heap_iterator_start(); 5433 // Start the iteration. 5434 space_iterator_ = new SpaceIterator(heap_); 5435 switch (filtering_) { 5436 case kFilterUnreachable: 5437 filter_ = new UnreachableObjectsFilter(heap_); 5438 break; 5439 default: 5440 break; 5441 } 5442 object_iterator_ = space_iterator_->next()->GetObjectIterator(); 5443 } 5444 5445 5446 HeapIterator::~HeapIterator() { 5447 heap_->heap_iterator_end(); 5448 #ifdef DEBUG 5449 // Assert that in filtering mode we have iterated through all 5450 // objects. Otherwise, heap will be left in an inconsistent state. 5451 if (filtering_ != kNoFiltering) { 5452 DCHECK_NULL(object_iterator_); 5453 } 5454 #endif 5455 delete space_iterator_; 5456 delete filter_; 5457 } 5458 5459 5460 HeapObject* HeapIterator::next() { 5461 if (filter_ == nullptr) return NextObject(); 5462 5463 HeapObject* obj = NextObject(); 5464 while ((obj != nullptr) && (filter_->SkipObject(obj))) obj = NextObject(); 5465 return obj; 5466 } 5467 5468 5469 HeapObject* HeapIterator::NextObject() { 5470 // No iterator means we are done. 5471 if (object_iterator_.get() == nullptr) return nullptr; 5472 5473 if (HeapObject* obj = object_iterator_.get()->Next()) { 5474 // If the current iterator has more objects we are fine. 5475 return obj; 5476 } else { 5477 // Go though the spaces looking for one that has objects. 5478 while (space_iterator_->has_next()) { 5479 object_iterator_ = space_iterator_->next()->GetObjectIterator(); 5480 if (HeapObject* obj = object_iterator_.get()->Next()) { 5481 return obj; 5482 } 5483 } 5484 } 5485 // Done with the last space. 5486 object_iterator_.reset(nullptr); 5487 return nullptr; 5488 } 5489 5490 5491 void Heap::UpdateTotalGCTime(double duration) { 5492 if (FLAG_trace_gc_verbose) { 5493 total_gc_time_ms_ += duration; 5494 } 5495 } 5496 5497 void Heap::ExternalStringTable::CleanUpNewSpaceStrings() { 5498 int last = 0; 5499 Isolate* isolate = heap_->isolate(); 5500 for (size_t i = 0; i < new_space_strings_.size(); ++i) { 5501 Object* o = new_space_strings_[i]; 5502 if (o->IsTheHole(isolate)) { 5503 continue; 5504 } 5505 // The real external string is already in one of these vectors and was or 5506 // will be processed. Re-processing it will add a duplicate to the vector. 5507 if (o->IsThinString()) continue; 5508 DCHECK(o->IsExternalString()); 5509 if (InNewSpace(o)) { 5510 new_space_strings_[last++] = o; 5511 } else { 5512 old_space_strings_.push_back(o); 5513 } 5514 } 5515 new_space_strings_.resize(last); 5516 } 5517 5518 void Heap::ExternalStringTable::CleanUpAll() { 5519 CleanUpNewSpaceStrings(); 5520 int last = 0; 5521 Isolate* isolate = heap_->isolate(); 5522 for (size_t i = 0; i < old_space_strings_.size(); ++i) { 5523 Object* o = old_space_strings_[i]; 5524 if (o->IsTheHole(isolate)) { 5525 continue; 5526 } 5527 // The real external string is already in one of these vectors and was or 5528 // will be processed. Re-processing it will add a duplicate to the vector. 5529 if (o->IsThinString()) continue; 5530 DCHECK(o->IsExternalString()); 5531 DCHECK(!InNewSpace(o)); 5532 old_space_strings_[last++] = o; 5533 } 5534 old_space_strings_.resize(last); 5535 #ifdef VERIFY_HEAP 5536 if (FLAG_verify_heap) { 5537 Verify(); 5538 } 5539 #endif 5540 } 5541 5542 void Heap::ExternalStringTable::TearDown() { 5543 for (size_t i = 0; i < new_space_strings_.size(); ++i) { 5544 Object* o = new_space_strings_[i]; 5545 // Dont finalize thin strings. 5546 if (o->IsThinString()) continue; 5547 heap_->FinalizeExternalString(ExternalString::cast(o)); 5548 } 5549 new_space_strings_.clear(); 5550 for (size_t i = 0; i < old_space_strings_.size(); ++i) { 5551 Object* o = old_space_strings_[i]; 5552 // Dont finalize thin strings. 5553 if (o->IsThinString()) continue; 5554 heap_->FinalizeExternalString(ExternalString::cast(o)); 5555 } 5556 old_space_strings_.clear(); 5557 } 5558 5559 5560 void Heap::RememberUnmappedPage(Address page, bool compacted) { 5561 // Tag the page pointer to make it findable in the dump file. 5562 if (compacted) { 5563 page ^= 0xC1EAD & (Page::kPageSize - 1); // Cleared. 5564 } else { 5565 page ^= 0x1D1ED & (Page::kPageSize - 1); // I died. 5566 } 5567 remembered_unmapped_pages_[remembered_unmapped_pages_index_] = page; 5568 remembered_unmapped_pages_index_++; 5569 remembered_unmapped_pages_index_ %= kRememberedUnmappedPages; 5570 } 5571 5572 void Heap::RegisterStrongRoots(Object** start, Object** end) { 5573 StrongRootsList* list = new StrongRootsList(); 5574 list->next = strong_roots_list_; 5575 list->start = start; 5576 list->end = end; 5577 strong_roots_list_ = list; 5578 } 5579 5580 5581 void Heap::UnregisterStrongRoots(Object** start) { 5582 StrongRootsList* prev = nullptr; 5583 StrongRootsList* list = strong_roots_list_; 5584 while (list != nullptr) { 5585 StrongRootsList* next = list->next; 5586 if (list->start == start) { 5587 if (prev) { 5588 prev->next = next; 5589 } else { 5590 strong_roots_list_ = next; 5591 } 5592 delete list; 5593 } else { 5594 prev = list; 5595 } 5596 list = next; 5597 } 5598 } 5599 5600 bool Heap::IsDeserializeLazyHandler(Code* code) { 5601 return (code == deserialize_lazy_handler() || 5602 code == deserialize_lazy_handler_wide() || 5603 code == deserialize_lazy_handler_extra_wide()); 5604 } 5605 5606 void Heap::SetDeserializeLazyHandler(Code* code) { 5607 set_deserialize_lazy_handler(code); 5608 } 5609 5610 void Heap::SetDeserializeLazyHandlerWide(Code* code) { 5611 set_deserialize_lazy_handler_wide(code); 5612 } 5613 5614 void Heap::SetDeserializeLazyHandlerExtraWide(Code* code) { 5615 set_deserialize_lazy_handler_extra_wide(code); 5616 } 5617 5618 void Heap::SetBuiltinsConstantsTable(FixedArray* cache) { 5619 set_builtins_constants_table(cache); 5620 } 5621 5622 size_t Heap::NumberOfTrackedHeapObjectTypes() { 5623 return ObjectStats::OBJECT_STATS_COUNT; 5624 } 5625 5626 5627 size_t Heap::ObjectCountAtLastGC(size_t index) { 5628 if (live_object_stats_ == nullptr || index >= ObjectStats::OBJECT_STATS_COUNT) 5629 return 0; 5630 return live_object_stats_->object_count_last_gc(index); 5631 } 5632 5633 5634 size_t Heap::ObjectSizeAtLastGC(size_t index) { 5635 if (live_object_stats_ == nullptr || index >= ObjectStats::OBJECT_STATS_COUNT) 5636 return 0; 5637 return live_object_stats_->object_size_last_gc(index); 5638 } 5639 5640 5641 bool Heap::GetObjectTypeName(size_t index, const char** object_type, 5642 const char** object_sub_type) { 5643 if (index >= ObjectStats::OBJECT_STATS_COUNT) return false; 5644 5645 switch (static_cast<int>(index)) { 5646 #define COMPARE_AND_RETURN_NAME(name) \ 5647 case name: \ 5648 *object_type = #name; \ 5649 *object_sub_type = ""; \ 5650 return true; 5651 INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME) 5652 #undef COMPARE_AND_RETURN_NAME 5653 5654 #define COMPARE_AND_RETURN_NAME(name) \ 5655 case ObjectStats::FIRST_VIRTUAL_TYPE + ObjectStats::name: \ 5656 *object_type = #name; \ 5657 *object_sub_type = ""; \ 5658 return true; 5659 VIRTUAL_INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME) 5660 #undef COMPARE_AND_RETURN_NAME 5661 } 5662 return false; 5663 } 5664 5665 size_t Heap::NumberOfNativeContexts() { 5666 int result = 0; 5667 Object* context = native_contexts_list(); 5668 while (!context->IsUndefined(isolate())) { 5669 ++result; 5670 Context* native_context = Context::cast(context); 5671 context = native_context->next_context_link(); 5672 } 5673 return result; 5674 } 5675 5676 size_t Heap::NumberOfDetachedContexts() { 5677 // The detached_contexts() array has two entries per detached context. 5678 return detached_contexts()->length() / 2; 5679 } 5680 5681 const char* AllocationSpaceName(AllocationSpace space) { 5682 switch (space) { 5683 case NEW_SPACE: 5684 return "NEW_SPACE"; 5685 case OLD_SPACE: 5686 return "OLD_SPACE"; 5687 case CODE_SPACE: 5688 return "CODE_SPACE"; 5689 case MAP_SPACE: 5690 return "MAP_SPACE"; 5691 case LO_SPACE: 5692 return "LO_SPACE"; 5693 case NEW_LO_SPACE: 5694 return "NEW_LO_SPACE"; 5695 case RO_SPACE: 5696 return "RO_SPACE"; 5697 default: 5698 UNREACHABLE(); 5699 } 5700 return nullptr; 5701 } 5702 5703 void VerifyPointersVisitor::VisitPointers(HeapObject* host, Object** start, 5704 Object** end) { 5705 VerifyPointers(host, reinterpret_cast<MaybeObject**>(start), 5706 reinterpret_cast<MaybeObject**>(end)); 5707 } 5708 5709 void VerifyPointersVisitor::VisitPointers(HeapObject* host, MaybeObject** start, 5710 MaybeObject** end) { 5711 VerifyPointers(host, start, end); 5712 } 5713 5714 void VerifyPointersVisitor::VisitRootPointers(Root root, 5715 const char* description, 5716 Object** start, Object** end) { 5717 VerifyPointers(nullptr, reinterpret_cast<MaybeObject**>(start), 5718 reinterpret_cast<MaybeObject**>(end)); 5719 } 5720 5721 void VerifyPointersVisitor::VerifyPointers(HeapObject* host, 5722 MaybeObject** start, 5723 MaybeObject** end) { 5724 for (MaybeObject** current = start; current < end; current++) { 5725 HeapObject* object; 5726 if ((*current)->ToStrongOrWeakHeapObject(&object)) { 5727 CHECK(heap_->Contains(object)); 5728 CHECK(object->map()->IsMap()); 5729 } else { 5730 CHECK((*current)->IsSmi() || (*current)->IsClearedWeakHeapObject()); 5731 } 5732 } 5733 } 5734 5735 void VerifySmisVisitor::VisitRootPointers(Root root, const char* description, 5736 Object** start, Object** end) { 5737 for (Object** current = start; current < end; current++) { 5738 CHECK((*current)->IsSmi()); 5739 } 5740 } 5741 5742 bool Heap::AllowedToBeMigrated(HeapObject* obj, AllocationSpace dst) { 5743 // Object migration is governed by the following rules: 5744 // 5745 // 1) Objects in new-space can be migrated to the old space 5746 // that matches their target space or they stay in new-space. 5747 // 2) Objects in old-space stay in the same space when migrating. 5748 // 3) Fillers (two or more words) can migrate due to left-trimming of 5749 // fixed arrays in new-space or old space. 5750 // 4) Fillers (one word) can never migrate, they are skipped by 5751 // incremental marking explicitly to prevent invalid pattern. 5752 // 5753 // Since this function is used for debugging only, we do not place 5754 // asserts here, but check everything explicitly. 5755 if (obj->map() == ReadOnlyRoots(this).one_pointer_filler_map()) return false; 5756 InstanceType type = obj->map()->instance_type(); 5757 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); 5758 AllocationSpace src = chunk->owner()->identity(); 5759 switch (src) { 5760 case NEW_SPACE: 5761 return dst == NEW_SPACE || dst == OLD_SPACE; 5762 case OLD_SPACE: 5763 return dst == OLD_SPACE; 5764 case CODE_SPACE: 5765 return dst == CODE_SPACE && type == CODE_TYPE; 5766 case MAP_SPACE: 5767 case LO_SPACE: 5768 case NEW_LO_SPACE: 5769 case RO_SPACE: 5770 return false; 5771 } 5772 UNREACHABLE(); 5773 } 5774 5775 void Heap::CreateObjectStats() { 5776 if (V8_LIKELY(FLAG_gc_stats == 0)) return; 5777 if (!live_object_stats_) { 5778 live_object_stats_ = new ObjectStats(this); 5779 } 5780 if (!dead_object_stats_) { 5781 dead_object_stats_ = new ObjectStats(this); 5782 } 5783 } 5784 5785 void AllocationObserver::AllocationStep(int bytes_allocated, 5786 Address soon_object, size_t size) { 5787 DCHECK_GE(bytes_allocated, 0); 5788 bytes_to_next_step_ -= bytes_allocated; 5789 if (bytes_to_next_step_ <= 0) { 5790 Step(static_cast<int>(step_size_ - bytes_to_next_step_), soon_object, size); 5791 step_size_ = GetNextStepSize(); 5792 bytes_to_next_step_ = step_size_; 5793 } 5794 DCHECK_GE(bytes_to_next_step_, 0); 5795 } 5796 5797 namespace { 5798 5799 Map* GcSafeMapOfCodeSpaceObject(HeapObject* object) { 5800 MapWord map_word = object->map_word(); 5801 return map_word.IsForwardingAddress() ? map_word.ToForwardingAddress()->map() 5802 : map_word.ToMap(); 5803 } 5804 5805 int GcSafeSizeOfCodeSpaceObject(HeapObject* object) { 5806 return object->SizeFromMap(GcSafeMapOfCodeSpaceObject(object)); 5807 } 5808 5809 Code* GcSafeCastToCode(Heap* heap, HeapObject* object, Address inner_pointer) { 5810 Code* code = reinterpret_cast<Code*>(object); 5811 DCHECK_NOT_NULL(code); 5812 DCHECK(heap->GcSafeCodeContains(code, inner_pointer)); 5813 return code; 5814 } 5815 5816 } // namespace 5817 5818 bool Heap::GcSafeCodeContains(HeapObject* code, Address addr) { 5819 Map* map = GcSafeMapOfCodeSpaceObject(code); 5820 DCHECK(map == ReadOnlyRoots(this).code_map()); 5821 if (InstructionStream::TryLookupCode(isolate(), addr) == code) return true; 5822 Address start = code->address(); 5823 Address end = code->address() + code->SizeFromMap(map); 5824 return start <= addr && addr < end; 5825 } 5826 5827 Code* Heap::GcSafeFindCodeForInnerPointer(Address inner_pointer) { 5828 Code* code = InstructionStream::TryLookupCode(isolate(), inner_pointer); 5829 if (code != nullptr) return code; 5830 5831 // Check if the inner pointer points into a large object chunk. 5832 LargePage* large_page = lo_space()->FindPage(inner_pointer); 5833 if (large_page != nullptr) { 5834 return GcSafeCastToCode(this, large_page->GetObject(), inner_pointer); 5835 } 5836 5837 DCHECK(code_space()->Contains(inner_pointer)); 5838 5839 // Iterate through the page until we reach the end or find an object starting 5840 // after the inner pointer. 5841 Page* page = Page::FromAddress(inner_pointer); 5842 DCHECK_EQ(page->owner(), code_space()); 5843 mark_compact_collector()->sweeper()->EnsurePageIsIterable(page); 5844 5845 Address addr = page->skip_list()->StartFor(inner_pointer); 5846 Address top = code_space()->top(); 5847 Address limit = code_space()->limit(); 5848 5849 while (true) { 5850 if (addr == top && addr != limit) { 5851 addr = limit; 5852 continue; 5853 } 5854 5855 HeapObject* obj = HeapObject::FromAddress(addr); 5856 int obj_size = GcSafeSizeOfCodeSpaceObject(obj); 5857 Address next_addr = addr + obj_size; 5858 if (next_addr > inner_pointer) 5859 return GcSafeCastToCode(this, obj, inner_pointer); 5860 addr = next_addr; 5861 } 5862 } 5863 5864 void Heap::WriteBarrierForCodeSlow(Code* code) { 5865 for (RelocIterator it(code, RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT)); 5866 !it.done(); it.next()) { 5867 GenerationalBarrierForCode(code, it.rinfo(), it.rinfo()->target_object()); 5868 MarkingBarrierForCode(code, it.rinfo(), it.rinfo()->target_object()); 5869 } 5870 } 5871 5872 void Heap::GenerationalBarrierSlow(HeapObject* object, Address slot, 5873 HeapObject* value) { 5874 Heap* heap = Heap::FromWritableHeapObject(object); 5875 heap->store_buffer()->InsertEntry(slot); 5876 } 5877 5878 void Heap::GenerationalBarrierForElementsSlow(Heap* heap, FixedArray* array, 5879 int offset, int length) { 5880 for (int i = 0; i < length; i++) { 5881 if (!InNewSpace(array->get(offset + i))) continue; 5882 heap->store_buffer()->InsertEntry( 5883 reinterpret_cast<Address>(array->RawFieldOfElementAt(offset + i))); 5884 } 5885 } 5886 5887 void Heap::GenerationalBarrierForCodeSlow(Code* host, RelocInfo* rinfo, 5888 HeapObject* object) { 5889 DCHECK(InNewSpace(object)); 5890 Page* source_page = Page::FromAddress(reinterpret_cast<Address>(host)); 5891 RelocInfo::Mode rmode = rinfo->rmode(); 5892 Address addr = rinfo->pc(); 5893 SlotType slot_type = SlotTypeForRelocInfoMode(rmode); 5894 if (rinfo->IsInConstantPool()) { 5895 addr = rinfo->constant_pool_entry_address(); 5896 if (RelocInfo::IsCodeTargetMode(rmode)) { 5897 slot_type = CODE_ENTRY_SLOT; 5898 } else { 5899 DCHECK(RelocInfo::IsEmbeddedObject(rmode)); 5900 slot_type = OBJECT_SLOT; 5901 } 5902 } 5903 RememberedSet<OLD_TO_NEW>::InsertTyped( 5904 source_page, reinterpret_cast<Address>(host), slot_type, addr); 5905 } 5906 5907 void Heap::MarkingBarrierSlow(HeapObject* object, Address slot, 5908 HeapObject* value) { 5909 Heap* heap = Heap::FromWritableHeapObject(object); 5910 heap->incremental_marking()->RecordWriteSlow( 5911 object, reinterpret_cast<HeapObjectReference**>(slot), value); 5912 } 5913 5914 void Heap::MarkingBarrierForElementsSlow(Heap* heap, HeapObject* object) { 5915 if (FLAG_concurrent_marking || 5916 heap->incremental_marking()->marking_state()->IsBlack(object)) { 5917 heap->incremental_marking()->RevisitObject(object); 5918 } 5919 } 5920 5921 void Heap::MarkingBarrierForCodeSlow(Code* host, RelocInfo* rinfo, 5922 HeapObject* object) { 5923 Heap* heap = Heap::FromWritableHeapObject(host); 5924 DCHECK(heap->incremental_marking()->IsMarking()); 5925 heap->incremental_marking()->RecordWriteIntoCode(host, rinfo, object); 5926 } 5927 5928 bool Heap::PageFlagsAreConsistent(HeapObject* object) { 5929 Heap* heap = Heap::FromWritableHeapObject(object); 5930 MemoryChunk* chunk = MemoryChunk::FromHeapObject(object); 5931 heap_internals::MemoryChunk* slim_chunk = 5932 heap_internals::MemoryChunk::FromHeapObject(object); 5933 5934 const bool generation_consistency = 5935 chunk->owner()->identity() != NEW_SPACE || 5936 (chunk->InNewSpace() && slim_chunk->InNewSpace()); 5937 const bool marking_consistency = 5938 !heap->incremental_marking()->IsMarking() || 5939 (chunk->IsFlagSet(MemoryChunk::INCREMENTAL_MARKING) && 5940 slim_chunk->IsMarking()); 5941 5942 return generation_consistency && marking_consistency; 5943 } 5944 5945 static_assert(MemoryChunk::Flag::INCREMENTAL_MARKING == 5946 heap_internals::MemoryChunk::kMarkingBit, 5947 "Incremental marking flag inconsistent"); 5948 static_assert(MemoryChunk::Flag::IN_FROM_SPACE == 5949 heap_internals::MemoryChunk::kFromSpaceBit, 5950 "From space flag inconsistent"); 5951 static_assert(MemoryChunk::Flag::IN_TO_SPACE == 5952 heap_internals::MemoryChunk::kToSpaceBit, 5953 "To space flag inconsistent"); 5954 static_assert(MemoryChunk::kFlagsOffset == 5955 heap_internals::MemoryChunk::kFlagsOffset, 5956 "Flag offset inconsistent"); 5957 5958 void Heap::SetEmbedderStackStateForNextFinalizaton( 5959 EmbedderHeapTracer::EmbedderStackState stack_state) { 5960 local_embedder_heap_tracer()->SetEmbedderStackStateForNextFinalization( 5961 stack_state); 5962 } 5963 5964 } // namespace internal 5965 } // namespace v8 5966