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 "src/accessors.h" 8 #include "src/api.h" 9 #include "src/ast/context-slot-cache.h" 10 #include "src/base/bits.h" 11 #include "src/base/once.h" 12 #include "src/base/utils/random-number-generator.h" 13 #include "src/bootstrapper.h" 14 #include "src/codegen.h" 15 #include "src/compilation-cache.h" 16 #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h" 17 #include "src/conversions.h" 18 #include "src/debug/debug.h" 19 #include "src/deoptimizer.h" 20 #include "src/global-handles.h" 21 #include "src/heap/array-buffer-tracker-inl.h" 22 #include "src/heap/code-stats.h" 23 #include "src/heap/gc-idle-time-handler.h" 24 #include "src/heap/gc-tracer.h" 25 #include "src/heap/incremental-marking.h" 26 #include "src/heap/mark-compact-inl.h" 27 #include "src/heap/mark-compact.h" 28 #include "src/heap/memory-reducer.h" 29 #include "src/heap/object-stats.h" 30 #include "src/heap/objects-visiting-inl.h" 31 #include "src/heap/objects-visiting.h" 32 #include "src/heap/remembered-set.h" 33 #include "src/heap/scavenge-job.h" 34 #include "src/heap/scavenger-inl.h" 35 #include "src/heap/store-buffer.h" 36 #include "src/interpreter/interpreter.h" 37 #include "src/regexp/jsregexp.h" 38 #include "src/runtime-profiler.h" 39 #include "src/snapshot/natives.h" 40 #include "src/snapshot/serializer-common.h" 41 #include "src/snapshot/snapshot.h" 42 #include "src/tracing/trace-event.h" 43 #include "src/type-feedback-vector.h" 44 #include "src/utils.h" 45 #include "src/v8.h" 46 #include "src/v8threads.h" 47 #include "src/vm-state-inl.h" 48 49 namespace v8 { 50 namespace internal { 51 52 53 struct Heap::StrongRootsList { 54 Object** start; 55 Object** end; 56 StrongRootsList* next; 57 }; 58 59 class IdleScavengeObserver : public AllocationObserver { 60 public: 61 IdleScavengeObserver(Heap& heap, intptr_t step_size) 62 : AllocationObserver(step_size), heap_(heap) {} 63 64 void Step(int bytes_allocated, Address, size_t) override { 65 heap_.ScheduleIdleScavengeIfNeeded(bytes_allocated); 66 } 67 68 private: 69 Heap& heap_; 70 }; 71 72 Heap::Heap() 73 : external_memory_(0), 74 external_memory_limit_(kExternalAllocationSoftLimit), 75 external_memory_at_last_mark_compact_(0), 76 isolate_(nullptr), 77 code_range_size_(0), 78 // semispace_size_ should be a power of 2 and old_generation_size_ should 79 // be a multiple of Page::kPageSize. 80 max_semi_space_size_(8 * (kPointerSize / 4) * MB), 81 initial_semispace_size_(MB), 82 max_old_generation_size_(700ul * (kPointerSize / 4) * MB), 83 initial_old_generation_size_(max_old_generation_size_ / 84 kInitalOldGenerationLimitFactor), 85 old_generation_size_configured_(false), 86 max_executable_size_(256ul * (kPointerSize / 4) * MB), 87 // Variables set based on semispace_size_ and old_generation_size_ in 88 // ConfigureHeap. 89 // Will be 4 * reserved_semispace_size_ to ensure that young 90 // generation can be aligned to its size. 91 maximum_committed_(0), 92 survived_since_last_expansion_(0), 93 survived_last_scavenge_(0), 94 always_allocate_scope_count_(0), 95 memory_pressure_level_(MemoryPressureLevel::kNone), 96 contexts_disposed_(0), 97 number_of_disposed_maps_(0), 98 global_ic_age_(0), 99 new_space_(nullptr), 100 old_space_(NULL), 101 code_space_(NULL), 102 map_space_(NULL), 103 lo_space_(NULL), 104 gc_state_(NOT_IN_GC), 105 gc_post_processing_depth_(0), 106 allocations_count_(0), 107 raw_allocations_hash_(0), 108 ms_count_(0), 109 gc_count_(0), 110 remembered_unmapped_pages_index_(0), 111 #ifdef DEBUG 112 allocation_timeout_(0), 113 #endif // DEBUG 114 old_generation_allocation_limit_(initial_old_generation_size_), 115 inline_allocation_disabled_(false), 116 total_regexp_code_generated_(0), 117 tracer_(nullptr), 118 promoted_objects_size_(0), 119 promotion_ratio_(0), 120 semi_space_copied_object_size_(0), 121 previous_semi_space_copied_object_size_(0), 122 semi_space_copied_rate_(0), 123 nodes_died_in_new_space_(0), 124 nodes_copied_in_new_space_(0), 125 nodes_promoted_(0), 126 maximum_size_scavenges_(0), 127 last_idle_notification_time_(0.0), 128 last_gc_time_(0.0), 129 scavenge_collector_(nullptr), 130 mark_compact_collector_(nullptr), 131 memory_allocator_(nullptr), 132 store_buffer_(nullptr), 133 incremental_marking_(nullptr), 134 gc_idle_time_handler_(nullptr), 135 memory_reducer_(nullptr), 136 live_object_stats_(nullptr), 137 dead_object_stats_(nullptr), 138 scavenge_job_(nullptr), 139 idle_scavenge_observer_(nullptr), 140 full_codegen_bytes_generated_(0), 141 crankshaft_codegen_bytes_generated_(0), 142 new_space_allocation_counter_(0), 143 old_generation_allocation_counter_at_last_gc_(0), 144 old_generation_size_at_last_gc_(0), 145 gcs_since_last_deopt_(0), 146 global_pretenuring_feedback_(nullptr), 147 ring_buffer_full_(false), 148 ring_buffer_end_(0), 149 promotion_queue_(this), 150 configured_(false), 151 current_gc_flags_(Heap::kNoGCFlags), 152 current_gc_callback_flags_(GCCallbackFlags::kNoGCCallbackFlags), 153 external_string_table_(this), 154 gc_callbacks_depth_(0), 155 deserialization_complete_(false), 156 strong_roots_list_(NULL), 157 heap_iterator_depth_(0), 158 embedder_heap_tracer_(nullptr), 159 force_oom_(false), 160 delay_sweeper_tasks_for_testing_(false) { 161 // Allow build-time customization of the max semispace size. Building 162 // V8 with snapshots and a non-default max semispace size is much 163 // easier if you can define it as part of the build environment. 164 #if defined(V8_MAX_SEMISPACE_SIZE) 165 max_semi_space_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE; 166 #endif 167 168 // Ensure old_generation_size_ is a multiple of kPageSize. 169 DCHECK((max_old_generation_size_ & (Page::kPageSize - 1)) == 0); 170 171 memset(roots_, 0, sizeof(roots_[0]) * kRootListLength); 172 set_native_contexts_list(NULL); 173 set_allocation_sites_list(Smi::kZero); 174 set_encountered_weak_collections(Smi::kZero); 175 set_encountered_weak_cells(Smi::kZero); 176 set_encountered_transition_arrays(Smi::kZero); 177 // Put a dummy entry in the remembered pages so we can find the list the 178 // minidump even if there are no real unmapped pages. 179 RememberUnmappedPage(NULL, false); 180 } 181 182 size_t Heap::Capacity() { 183 if (!HasBeenSetUp()) return 0; 184 185 return new_space_->Capacity() + OldGenerationCapacity(); 186 } 187 188 size_t Heap::OldGenerationCapacity() { 189 if (!HasBeenSetUp()) return 0; 190 191 return old_space_->Capacity() + code_space_->Capacity() + 192 map_space_->Capacity() + lo_space_->SizeOfObjects(); 193 } 194 195 size_t Heap::CommittedOldGenerationMemory() { 196 if (!HasBeenSetUp()) return 0; 197 198 return old_space_->CommittedMemory() + code_space_->CommittedMemory() + 199 map_space_->CommittedMemory() + lo_space_->Size(); 200 } 201 202 size_t Heap::CommittedMemory() { 203 if (!HasBeenSetUp()) return 0; 204 205 return new_space_->CommittedMemory() + CommittedOldGenerationMemory(); 206 } 207 208 209 size_t Heap::CommittedPhysicalMemory() { 210 if (!HasBeenSetUp()) return 0; 211 212 return new_space_->CommittedPhysicalMemory() + 213 old_space_->CommittedPhysicalMemory() + 214 code_space_->CommittedPhysicalMemory() + 215 map_space_->CommittedPhysicalMemory() + 216 lo_space_->CommittedPhysicalMemory(); 217 } 218 219 size_t Heap::CommittedMemoryExecutable() { 220 if (!HasBeenSetUp()) return 0; 221 222 return static_cast<size_t>(memory_allocator()->SizeExecutable()); 223 } 224 225 226 void Heap::UpdateMaximumCommitted() { 227 if (!HasBeenSetUp()) return; 228 229 const size_t current_committed_memory = CommittedMemory(); 230 if (current_committed_memory > maximum_committed_) { 231 maximum_committed_ = current_committed_memory; 232 } 233 } 234 235 size_t Heap::Available() { 236 if (!HasBeenSetUp()) return 0; 237 238 size_t total = 0; 239 AllSpaces spaces(this); 240 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { 241 total += space->Available(); 242 } 243 return total; 244 } 245 246 247 bool Heap::HasBeenSetUp() { 248 return old_space_ != NULL && code_space_ != NULL && map_space_ != NULL && 249 lo_space_ != NULL; 250 } 251 252 253 GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space, 254 const char** reason) { 255 // Is global GC requested? 256 if (space != NEW_SPACE) { 257 isolate_->counters()->gc_compactor_caused_by_request()->Increment(); 258 *reason = "GC in old space requested"; 259 return MARK_COMPACTOR; 260 } 261 262 if (FLAG_gc_global || (FLAG_stress_compaction && (gc_count_ & 1) != 0)) { 263 *reason = "GC in old space forced by flags"; 264 return MARK_COMPACTOR; 265 } 266 267 if (incremental_marking()->NeedsFinalization() && 268 AllocationLimitOvershotByLargeMargin()) { 269 *reason = "Incremental marking needs finalization"; 270 return MARK_COMPACTOR; 271 } 272 273 // Is there enough space left in OLD to guarantee that a scavenge can 274 // succeed? 275 // 276 // Note that MemoryAllocator->MaxAvailable() undercounts the memory available 277 // for object promotion. It counts only the bytes that the memory 278 // allocator has not yet allocated from the OS and assigned to any space, 279 // and does not count available bytes already in the old space or code 280 // space. Undercounting is safe---we may get an unrequested full GC when 281 // a scavenge would have succeeded. 282 if (memory_allocator()->MaxAvailable() <= new_space_->Size()) { 283 isolate_->counters() 284 ->gc_compactor_caused_by_oldspace_exhaustion() 285 ->Increment(); 286 *reason = "scavenge might not succeed"; 287 return MARK_COMPACTOR; 288 } 289 290 // Default 291 *reason = NULL; 292 return YoungGenerationCollector(); 293 } 294 295 296 // TODO(1238405): Combine the infrastructure for --heap-stats and 297 // --log-gc to avoid the complicated preprocessor and flag testing. 298 void Heap::ReportStatisticsBeforeGC() { 299 // Heap::ReportHeapStatistics will also log NewSpace statistics when 300 // compiled --log-gc is set. The following logic is used to avoid 301 // double logging. 302 #ifdef DEBUG 303 if (FLAG_heap_stats || FLAG_log_gc) new_space_->CollectStatistics(); 304 if (FLAG_heap_stats) { 305 ReportHeapStatistics("Before GC"); 306 } else if (FLAG_log_gc) { 307 new_space_->ReportStatistics(); 308 } 309 if (FLAG_heap_stats || FLAG_log_gc) new_space_->ClearHistograms(); 310 #else 311 if (FLAG_log_gc) { 312 new_space_->CollectStatistics(); 313 new_space_->ReportStatistics(); 314 new_space_->ClearHistograms(); 315 } 316 #endif // DEBUG 317 } 318 319 320 void Heap::PrintShortHeapStatistics() { 321 if (!FLAG_trace_gc_verbose) return; 322 PrintIsolate(isolate_, "Memory allocator, used: %6" PRIuS 323 " KB," 324 " available: %6" PRIuS " KB\n", 325 memory_allocator()->Size() / KB, 326 memory_allocator()->Available() / KB); 327 PrintIsolate(isolate_, "New space, used: %6" PRIuS 328 " KB" 329 ", available: %6" PRIuS 330 " KB" 331 ", committed: %6" PRIuS " KB\n", 332 new_space_->Size() / KB, new_space_->Available() / KB, 333 new_space_->CommittedMemory() / KB); 334 PrintIsolate(isolate_, "Old space, used: %6" PRIuS 335 " KB" 336 ", available: %6" PRIuS 337 " KB" 338 ", committed: %6" PRIuS " KB\n", 339 old_space_->SizeOfObjects() / KB, old_space_->Available() / KB, 340 old_space_->CommittedMemory() / KB); 341 PrintIsolate(isolate_, "Code space, used: %6" PRIuS 342 " KB" 343 ", available: %6" PRIuS 344 " KB" 345 ", committed: %6" PRIuS "KB\n", 346 code_space_->SizeOfObjects() / KB, code_space_->Available() / KB, 347 code_space_->CommittedMemory() / KB); 348 PrintIsolate(isolate_, "Map space, used: %6" PRIuS 349 " KB" 350 ", available: %6" PRIuS 351 " KB" 352 ", committed: %6" PRIuS " KB\n", 353 map_space_->SizeOfObjects() / KB, map_space_->Available() / KB, 354 map_space_->CommittedMemory() / KB); 355 PrintIsolate(isolate_, "Large object space, used: %6" PRIuS 356 " KB" 357 ", available: %6" PRIuS 358 " KB" 359 ", committed: %6" PRIuS " KB\n", 360 lo_space_->SizeOfObjects() / KB, lo_space_->Available() / KB, 361 lo_space_->CommittedMemory() / KB); 362 PrintIsolate(isolate_, "All spaces, used: %6" PRIuS 363 " KB" 364 ", available: %6" PRIuS 365 " KB" 366 ", committed: %6" PRIuS "KB\n", 367 this->SizeOfObjects() / KB, this->Available() / KB, 368 this->CommittedMemory() / KB); 369 PrintIsolate(isolate_, "External memory reported: %6" PRId64 " KB\n", 370 external_memory_ / KB); 371 PrintIsolate(isolate_, "Total time spent in GC : %.1f ms\n", 372 total_gc_time_ms_); 373 } 374 375 // TODO(1238405): Combine the infrastructure for --heap-stats and 376 // --log-gc to avoid the complicated preprocessor and flag testing. 377 void Heap::ReportStatisticsAfterGC() { 378 // Similar to the before GC, we use some complicated logic to ensure that 379 // NewSpace statistics are logged exactly once when --log-gc is turned on. 380 #if defined(DEBUG) 381 if (FLAG_heap_stats) { 382 new_space_->CollectStatistics(); 383 ReportHeapStatistics("After GC"); 384 } else if (FLAG_log_gc) { 385 new_space_->ReportStatistics(); 386 } 387 #else 388 if (FLAG_log_gc) new_space_->ReportStatistics(); 389 #endif // DEBUG 390 for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount); 391 ++i) { 392 int count = deferred_counters_[i]; 393 deferred_counters_[i] = 0; 394 while (count > 0) { 395 count--; 396 isolate()->CountUsage(static_cast<v8::Isolate::UseCounterFeature>(i)); 397 } 398 } 399 } 400 401 402 void Heap::IncrementDeferredCount(v8::Isolate::UseCounterFeature feature) { 403 deferred_counters_[feature]++; 404 } 405 406 bool Heap::UncommitFromSpace() { return new_space_->UncommitFromSpace(); } 407 408 void Heap::GarbageCollectionPrologue() { 409 { 410 AllowHeapAllocation for_the_first_part_of_prologue; 411 gc_count_++; 412 413 #ifdef VERIFY_HEAP 414 if (FLAG_verify_heap) { 415 Verify(); 416 } 417 #endif 418 } 419 420 // Reset GC statistics. 421 promoted_objects_size_ = 0; 422 previous_semi_space_copied_object_size_ = semi_space_copied_object_size_; 423 semi_space_copied_object_size_ = 0; 424 nodes_died_in_new_space_ = 0; 425 nodes_copied_in_new_space_ = 0; 426 nodes_promoted_ = 0; 427 428 UpdateMaximumCommitted(); 429 430 #ifdef DEBUG 431 DCHECK(!AllowHeapAllocation::IsAllowed() && gc_state_ == NOT_IN_GC); 432 433 if (FLAG_gc_verbose) Print(); 434 435 ReportStatisticsBeforeGC(); 436 #endif // DEBUG 437 438 if (new_space_->IsAtMaximumCapacity()) { 439 maximum_size_scavenges_++; 440 } else { 441 maximum_size_scavenges_ = 0; 442 } 443 CheckNewSpaceExpansionCriteria(); 444 UpdateNewSpaceAllocationCounter(); 445 store_buffer()->MoveAllEntriesToRememberedSet(); 446 } 447 448 size_t Heap::SizeOfObjects() { 449 size_t total = 0; 450 AllSpaces spaces(this); 451 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { 452 total += space->SizeOfObjects(); 453 } 454 return total; 455 } 456 457 458 const char* Heap::GetSpaceName(int idx) { 459 switch (idx) { 460 case NEW_SPACE: 461 return "new_space"; 462 case OLD_SPACE: 463 return "old_space"; 464 case MAP_SPACE: 465 return "map_space"; 466 case CODE_SPACE: 467 return "code_space"; 468 case LO_SPACE: 469 return "large_object_space"; 470 default: 471 UNREACHABLE(); 472 } 473 return nullptr; 474 } 475 476 477 void Heap::RepairFreeListsAfterDeserialization() { 478 PagedSpaces spaces(this); 479 for (PagedSpace* space = spaces.next(); space != NULL; 480 space = spaces.next()) { 481 space->RepairFreeListsAfterDeserialization(); 482 } 483 } 484 485 void Heap::MergeAllocationSitePretenuringFeedback( 486 const base::HashMap& local_pretenuring_feedback) { 487 AllocationSite* site = nullptr; 488 for (base::HashMap::Entry* local_entry = local_pretenuring_feedback.Start(); 489 local_entry != nullptr; 490 local_entry = local_pretenuring_feedback.Next(local_entry)) { 491 site = reinterpret_cast<AllocationSite*>(local_entry->key); 492 MapWord map_word = site->map_word(); 493 if (map_word.IsForwardingAddress()) { 494 site = AllocationSite::cast(map_word.ToForwardingAddress()); 495 } 496 497 // We have not validated the allocation site yet, since we have not 498 // dereferenced the site during collecting information. 499 // This is an inlined check of AllocationMemento::IsValid. 500 if (!site->IsAllocationSite() || site->IsZombie()) continue; 501 502 int value = 503 static_cast<int>(reinterpret_cast<intptr_t>(local_entry->value)); 504 DCHECK_GT(value, 0); 505 506 if (site->IncrementMementoFoundCount(value)) { 507 global_pretenuring_feedback_->LookupOrInsert(site, 508 ObjectHash(site->address())); 509 } 510 } 511 } 512 513 514 class Heap::PretenuringScope { 515 public: 516 explicit PretenuringScope(Heap* heap) : heap_(heap) { 517 heap_->global_pretenuring_feedback_ = 518 new base::HashMap(kInitialFeedbackCapacity); 519 } 520 521 ~PretenuringScope() { 522 delete heap_->global_pretenuring_feedback_; 523 heap_->global_pretenuring_feedback_ = nullptr; 524 } 525 526 private: 527 Heap* heap_; 528 }; 529 530 531 void Heap::ProcessPretenuringFeedback() { 532 bool trigger_deoptimization = false; 533 if (FLAG_allocation_site_pretenuring) { 534 int tenure_decisions = 0; 535 int dont_tenure_decisions = 0; 536 int allocation_mementos_found = 0; 537 int allocation_sites = 0; 538 int active_allocation_sites = 0; 539 540 AllocationSite* site = nullptr; 541 542 // Step 1: Digest feedback for recorded allocation sites. 543 bool maximum_size_scavenge = MaximumSizeScavenge(); 544 for (base::HashMap::Entry* e = global_pretenuring_feedback_->Start(); 545 e != nullptr; e = global_pretenuring_feedback_->Next(e)) { 546 allocation_sites++; 547 site = reinterpret_cast<AllocationSite*>(e->key); 548 int found_count = site->memento_found_count(); 549 // An entry in the storage does not imply that the count is > 0 because 550 // allocation sites might have been reset due to too many objects dying 551 // in old space. 552 if (found_count > 0) { 553 DCHECK(site->IsAllocationSite()); 554 active_allocation_sites++; 555 allocation_mementos_found += found_count; 556 if (site->DigestPretenuringFeedback(maximum_size_scavenge)) { 557 trigger_deoptimization = true; 558 } 559 if (site->GetPretenureMode() == TENURED) { 560 tenure_decisions++; 561 } else { 562 dont_tenure_decisions++; 563 } 564 } 565 } 566 567 // Step 2: Deopt maybe tenured allocation sites if necessary. 568 bool deopt_maybe_tenured = DeoptMaybeTenuredAllocationSites(); 569 if (deopt_maybe_tenured) { 570 Object* list_element = allocation_sites_list(); 571 while (list_element->IsAllocationSite()) { 572 site = AllocationSite::cast(list_element); 573 DCHECK(site->IsAllocationSite()); 574 allocation_sites++; 575 if (site->IsMaybeTenure()) { 576 site->set_deopt_dependent_code(true); 577 trigger_deoptimization = true; 578 } 579 list_element = site->weak_next(); 580 } 581 } 582 583 if (trigger_deoptimization) { 584 isolate_->stack_guard()->RequestDeoptMarkedAllocationSites(); 585 } 586 587 if (FLAG_trace_pretenuring_statistics && 588 (allocation_mementos_found > 0 || tenure_decisions > 0 || 589 dont_tenure_decisions > 0)) { 590 PrintIsolate(isolate(), 591 "pretenuring: deopt_maybe_tenured=%d visited_sites=%d " 592 "active_sites=%d " 593 "mementos=%d tenured=%d not_tenured=%d\n", 594 deopt_maybe_tenured ? 1 : 0, allocation_sites, 595 active_allocation_sites, allocation_mementos_found, 596 tenure_decisions, dont_tenure_decisions); 597 } 598 } 599 } 600 601 602 void Heap::DeoptMarkedAllocationSites() { 603 // TODO(hpayer): If iterating over the allocation sites list becomes a 604 // performance issue, use a cache data structure in heap instead. 605 Object* list_element = allocation_sites_list(); 606 while (list_element->IsAllocationSite()) { 607 AllocationSite* site = AllocationSite::cast(list_element); 608 if (site->deopt_dependent_code()) { 609 site->dependent_code()->MarkCodeForDeoptimization( 610 isolate_, DependentCode::kAllocationSiteTenuringChangedGroup); 611 site->set_deopt_dependent_code(false); 612 } 613 list_element = site->weak_next(); 614 } 615 Deoptimizer::DeoptimizeMarkedCode(isolate_); 616 } 617 618 619 void Heap::GarbageCollectionEpilogue() { 620 // In release mode, we only zap the from space under heap verification. 621 if (Heap::ShouldZapGarbage()) { 622 ZapFromSpace(); 623 } 624 625 #ifdef VERIFY_HEAP 626 if (FLAG_verify_heap) { 627 Verify(); 628 } 629 #endif 630 631 AllowHeapAllocation for_the_rest_of_the_epilogue; 632 633 #ifdef DEBUG 634 if (FLAG_print_global_handles) isolate_->global_handles()->Print(); 635 if (FLAG_print_handles) PrintHandles(); 636 if (FLAG_gc_verbose) Print(); 637 if (FLAG_code_stats) ReportCodeStatistics("After GC"); 638 if (FLAG_check_handle_count) CheckHandleCount(); 639 #endif 640 if (FLAG_deopt_every_n_garbage_collections > 0) { 641 // TODO(jkummerow/ulan/jarin): This is not safe! We can't assume that 642 // the topmost optimized frame can be deoptimized safely, because it 643 // might not have a lazy bailout point right after its current PC. 644 if (++gcs_since_last_deopt_ == FLAG_deopt_every_n_garbage_collections) { 645 Deoptimizer::DeoptimizeAll(isolate()); 646 gcs_since_last_deopt_ = 0; 647 } 648 } 649 650 UpdateMaximumCommitted(); 651 652 isolate_->counters()->alive_after_last_gc()->Set( 653 static_cast<int>(SizeOfObjects())); 654 655 isolate_->counters()->string_table_capacity()->Set( 656 string_table()->Capacity()); 657 isolate_->counters()->number_of_symbols()->Set( 658 string_table()->NumberOfElements()); 659 660 if (CommittedMemory() > 0) { 661 isolate_->counters()->external_fragmentation_total()->AddSample( 662 static_cast<int>(100 - (SizeOfObjects() * 100.0) / CommittedMemory())); 663 664 isolate_->counters()->heap_fraction_new_space()->AddSample(static_cast<int>( 665 (new_space()->CommittedMemory() * 100.0) / CommittedMemory())); 666 isolate_->counters()->heap_fraction_old_space()->AddSample(static_cast<int>( 667 (old_space()->CommittedMemory() * 100.0) / CommittedMemory())); 668 isolate_->counters()->heap_fraction_code_space()->AddSample( 669 static_cast<int>((code_space()->CommittedMemory() * 100.0) / 670 CommittedMemory())); 671 isolate_->counters()->heap_fraction_map_space()->AddSample(static_cast<int>( 672 (map_space()->CommittedMemory() * 100.0) / CommittedMemory())); 673 isolate_->counters()->heap_fraction_lo_space()->AddSample(static_cast<int>( 674 (lo_space()->CommittedMemory() * 100.0) / CommittedMemory())); 675 676 isolate_->counters()->heap_sample_total_committed()->AddSample( 677 static_cast<int>(CommittedMemory() / KB)); 678 isolate_->counters()->heap_sample_total_used()->AddSample( 679 static_cast<int>(SizeOfObjects() / KB)); 680 isolate_->counters()->heap_sample_map_space_committed()->AddSample( 681 static_cast<int>(map_space()->CommittedMemory() / KB)); 682 isolate_->counters()->heap_sample_code_space_committed()->AddSample( 683 static_cast<int>(code_space()->CommittedMemory() / KB)); 684 685 isolate_->counters()->heap_sample_maximum_committed()->AddSample( 686 static_cast<int>(MaximumCommittedMemory() / KB)); 687 } 688 689 #define UPDATE_COUNTERS_FOR_SPACE(space) \ 690 isolate_->counters()->space##_bytes_available()->Set( \ 691 static_cast<int>(space()->Available())); \ 692 isolate_->counters()->space##_bytes_committed()->Set( \ 693 static_cast<int>(space()->CommittedMemory())); \ 694 isolate_->counters()->space##_bytes_used()->Set( \ 695 static_cast<int>(space()->SizeOfObjects())); 696 #define UPDATE_FRAGMENTATION_FOR_SPACE(space) \ 697 if (space()->CommittedMemory() > 0) { \ 698 isolate_->counters()->external_fragmentation_##space()->AddSample( \ 699 static_cast<int>(100 - \ 700 (space()->SizeOfObjects() * 100.0) / \ 701 space()->CommittedMemory())); \ 702 } 703 #define UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(space) \ 704 UPDATE_COUNTERS_FOR_SPACE(space) \ 705 UPDATE_FRAGMENTATION_FOR_SPACE(space) 706 707 UPDATE_COUNTERS_FOR_SPACE(new_space) 708 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_space) 709 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(code_space) 710 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(map_space) 711 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(lo_space) 712 #undef UPDATE_COUNTERS_FOR_SPACE 713 #undef UPDATE_FRAGMENTATION_FOR_SPACE 714 #undef UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE 715 716 #ifdef DEBUG 717 ReportStatisticsAfterGC(); 718 #endif // DEBUG 719 720 // Remember the last top pointer so that we can later find out 721 // whether we allocated in new space since the last GC. 722 new_space_top_after_last_gc_ = new_space()->top(); 723 last_gc_time_ = MonotonicallyIncreasingTimeInMs(); 724 725 ReduceNewSpaceSize(); 726 } 727 728 729 void Heap::PreprocessStackTraces() { 730 WeakFixedArray::Iterator iterator(weak_stack_trace_list()); 731 FixedArray* elements; 732 while ((elements = iterator.Next<FixedArray>())) { 733 for (int j = 1; j < elements->length(); j += 4) { 734 Object* maybe_code = elements->get(j + 2); 735 // If GC happens while adding a stack trace to the weak fixed array, 736 // which has been copied into a larger backing store, we may run into 737 // a stack trace that has already been preprocessed. Guard against this. 738 if (!maybe_code->IsAbstractCode()) break; 739 AbstractCode* abstract_code = AbstractCode::cast(maybe_code); 740 int offset = Smi::cast(elements->get(j + 3))->value(); 741 int pos = abstract_code->SourcePosition(offset); 742 elements->set(j + 2, Smi::FromInt(pos)); 743 } 744 } 745 // We must not compact the weak fixed list here, as we may be in the middle 746 // of writing to it, when the GC triggered. Instead, we reset the root value. 747 set_weak_stack_trace_list(Smi::kZero); 748 } 749 750 751 class GCCallbacksScope { 752 public: 753 explicit GCCallbacksScope(Heap* heap) : heap_(heap) { 754 heap_->gc_callbacks_depth_++; 755 } 756 ~GCCallbacksScope() { heap_->gc_callbacks_depth_--; } 757 758 bool CheckReenter() { return heap_->gc_callbacks_depth_ == 1; } 759 760 private: 761 Heap* heap_; 762 }; 763 764 765 void Heap::HandleGCRequest() { 766 if (HighMemoryPressure()) { 767 incremental_marking()->reset_request_type(); 768 CheckMemoryPressure(); 769 } else if (incremental_marking()->request_type() == 770 IncrementalMarking::COMPLETE_MARKING) { 771 incremental_marking()->reset_request_type(); 772 CollectAllGarbage(current_gc_flags_, 773 GarbageCollectionReason::kFinalizeMarkingViaStackGuard, 774 current_gc_callback_flags_); 775 } else if (incremental_marking()->request_type() == 776 IncrementalMarking::FINALIZATION && 777 incremental_marking()->IsMarking() && 778 !incremental_marking()->finalize_marking_completed()) { 779 incremental_marking()->reset_request_type(); 780 FinalizeIncrementalMarking( 781 GarbageCollectionReason::kFinalizeMarkingViaStackGuard); 782 } 783 } 784 785 786 void Heap::ScheduleIdleScavengeIfNeeded(int bytes_allocated) { 787 scavenge_job_->ScheduleIdleTaskIfNeeded(this, bytes_allocated); 788 } 789 790 void Heap::FinalizeIncrementalMarking(GarbageCollectionReason gc_reason) { 791 if (FLAG_trace_incremental_marking) { 792 isolate()->PrintWithTimestamp( 793 "[IncrementalMarking] (%s).\n", 794 Heap::GarbageCollectionReasonToString(gc_reason)); 795 } 796 797 HistogramTimerScope incremental_marking_scope( 798 isolate()->counters()->gc_incremental_marking_finalize()); 799 TRACE_EVENT0("v8", "V8.GCIncrementalMarkingFinalize"); 800 TRACE_GC(tracer(), GCTracer::Scope::MC_INCREMENTAL_FINALIZE); 801 802 { 803 GCCallbacksScope scope(this); 804 if (scope.CheckReenter()) { 805 AllowHeapAllocation allow_allocation; 806 TRACE_GC(tracer(), GCTracer::Scope::MC_INCREMENTAL_EXTERNAL_PROLOGUE); 807 VMState<EXTERNAL> state(isolate_); 808 HandleScope handle_scope(isolate_); 809 CallGCPrologueCallbacks(kGCTypeIncrementalMarking, kNoGCCallbackFlags); 810 } 811 } 812 incremental_marking()->FinalizeIncrementally(); 813 { 814 GCCallbacksScope scope(this); 815 if (scope.CheckReenter()) { 816 AllowHeapAllocation allow_allocation; 817 TRACE_GC(tracer(), GCTracer::Scope::MC_INCREMENTAL_EXTERNAL_EPILOGUE); 818 VMState<EXTERNAL> state(isolate_); 819 HandleScope handle_scope(isolate_); 820 CallGCEpilogueCallbacks(kGCTypeIncrementalMarking, kNoGCCallbackFlags); 821 } 822 } 823 } 824 825 826 HistogramTimer* Heap::GCTypeTimer(GarbageCollector collector) { 827 if (IsYoungGenerationCollector(collector)) { 828 return isolate_->counters()->gc_scavenger(); 829 } else { 830 if (!incremental_marking()->IsStopped()) { 831 if (ShouldReduceMemory()) { 832 return isolate_->counters()->gc_finalize_reduce_memory(); 833 } else { 834 return isolate_->counters()->gc_finalize(); 835 } 836 } else { 837 return isolate_->counters()->gc_compactor(); 838 } 839 } 840 } 841 842 void Heap::CollectAllGarbage(int flags, GarbageCollectionReason gc_reason, 843 const v8::GCCallbackFlags gc_callback_flags) { 844 // Since we are ignoring the return value, the exact choice of space does 845 // not matter, so long as we do not specify NEW_SPACE, which would not 846 // cause a full GC. 847 set_current_gc_flags(flags); 848 CollectGarbage(OLD_SPACE, gc_reason, gc_callback_flags); 849 set_current_gc_flags(kNoGCFlags); 850 } 851 852 void Heap::CollectAllAvailableGarbage(GarbageCollectionReason gc_reason) { 853 // Since we are ignoring the return value, the exact choice of space does 854 // not matter, so long as we do not specify NEW_SPACE, which would not 855 // cause a full GC. 856 // Major GC would invoke weak handle callbacks on weakly reachable 857 // handles, but won't collect weakly reachable objects until next 858 // major GC. Therefore if we collect aggressively and weak handle callback 859 // has been invoked, we rerun major GC to release objects which become 860 // garbage. 861 // Note: as weak callbacks can execute arbitrary code, we cannot 862 // hope that eventually there will be no weak callbacks invocations. 863 // Therefore stop recollecting after several attempts. 864 if (isolate()->concurrent_recompilation_enabled()) { 865 // The optimizing compiler may be unnecessarily holding on to memory. 866 DisallowHeapAllocation no_recursive_gc; 867 isolate()->optimizing_compile_dispatcher()->Flush( 868 OptimizingCompileDispatcher::BlockingBehavior::kDontBlock); 869 } 870 isolate()->ClearSerializerData(); 871 set_current_gc_flags(kMakeHeapIterableMask | kReduceMemoryFootprintMask); 872 isolate_->compilation_cache()->Clear(); 873 const int kMaxNumberOfAttempts = 7; 874 const int kMinNumberOfAttempts = 2; 875 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { 876 if (!CollectGarbage(MARK_COMPACTOR, gc_reason, NULL, 877 v8::kGCCallbackFlagCollectAllAvailableGarbage) && 878 attempt + 1 >= kMinNumberOfAttempts) { 879 break; 880 } 881 } 882 set_current_gc_flags(kNoGCFlags); 883 new_space_->Shrink(); 884 UncommitFromSpace(); 885 } 886 887 void Heap::ReportExternalMemoryPressure() { 888 if (external_memory_ > 889 (external_memory_at_last_mark_compact_ + external_memory_hard_limit())) { 890 CollectAllGarbage( 891 kReduceMemoryFootprintMask | kFinalizeIncrementalMarkingMask, 892 GarbageCollectionReason::kExternalMemoryPressure, 893 static_cast<GCCallbackFlags>(kGCCallbackFlagCollectAllAvailableGarbage | 894 kGCCallbackFlagCollectAllExternalMemory)); 895 return; 896 } 897 if (incremental_marking()->IsStopped()) { 898 if (incremental_marking()->CanBeActivated()) { 899 StartIncrementalMarking( 900 i::Heap::kNoGCFlags, GarbageCollectionReason::kExternalMemoryPressure, 901 static_cast<GCCallbackFlags>( 902 kGCCallbackFlagSynchronousPhantomCallbackProcessing | 903 kGCCallbackFlagCollectAllExternalMemory)); 904 } else { 905 CollectAllGarbage(i::Heap::kNoGCFlags, 906 GarbageCollectionReason::kExternalMemoryPressure, 907 kGCCallbackFlagSynchronousPhantomCallbackProcessing); 908 } 909 } else { 910 // Incremental marking is turned on an has already been started. 911 const double pressure = 912 static_cast<double>(external_memory_ - 913 external_memory_at_last_mark_compact_ - 914 kExternalAllocationSoftLimit) / 915 external_memory_hard_limit(); 916 DCHECK_GE(1, pressure); 917 const double kMaxStepSizeOnExternalLimit = 25; 918 const double deadline = MonotonicallyIncreasingTimeInMs() + 919 pressure * kMaxStepSizeOnExternalLimit; 920 incremental_marking()->AdvanceIncrementalMarking( 921 deadline, IncrementalMarking::GC_VIA_STACK_GUARD, 922 IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8); 923 } 924 } 925 926 927 void Heap::EnsureFillerObjectAtTop() { 928 // There may be an allocation memento behind objects in new space. Upon 929 // evacuation of a non-full new space (or if we are on the last page) there 930 // may be uninitialized memory behind top. We fill the remainder of the page 931 // with a filler. 932 Address to_top = new_space_->top(); 933 Page* page = Page::FromAddress(to_top - kPointerSize); 934 if (page->Contains(to_top)) { 935 int remaining_in_page = static_cast<int>(page->area_end() - to_top); 936 CreateFillerObjectAt(to_top, remaining_in_page, ClearRecordedSlots::kNo); 937 } 938 } 939 940 bool Heap::CollectGarbage(GarbageCollector collector, 941 GarbageCollectionReason gc_reason, 942 const char* collector_reason, 943 const v8::GCCallbackFlags gc_callback_flags) { 944 // The VM is in the GC state until exiting this function. 945 VMState<GC> state(isolate_); 946 947 #ifdef DEBUG 948 // Reset the allocation timeout to the GC interval, but make sure to 949 // allow at least a few allocations after a collection. The reason 950 // for this is that we have a lot of allocation sequences and we 951 // assume that a garbage collection will allow the subsequent 952 // allocation attempts to go through. 953 allocation_timeout_ = Max(6, FLAG_gc_interval); 954 #endif 955 956 EnsureFillerObjectAtTop(); 957 958 if (IsYoungGenerationCollector(collector) && 959 !incremental_marking()->IsStopped()) { 960 if (FLAG_trace_incremental_marking) { 961 isolate()->PrintWithTimestamp( 962 "[IncrementalMarking] Scavenge during marking.\n"); 963 } 964 } 965 966 if (collector == MARK_COMPACTOR && FLAG_incremental_marking && 967 !ShouldFinalizeIncrementalMarking() && !ShouldAbortIncrementalMarking() && 968 !incremental_marking()->IsStopped() && 969 !incremental_marking()->should_hurry() && 970 !incremental_marking()->NeedsFinalization() && 971 !IsCloseToOutOfMemory(new_space_->Capacity())) { 972 if (!incremental_marking()->IsComplete() && 973 !mark_compact_collector()->marking_deque()->IsEmpty() && 974 !FLAG_gc_global) { 975 if (FLAG_trace_incremental_marking) { 976 isolate()->PrintWithTimestamp( 977 "[IncrementalMarking] Delaying MarkSweep.\n"); 978 } 979 collector = YoungGenerationCollector(); 980 collector_reason = "incremental marking delaying mark-sweep"; 981 } 982 } 983 984 bool next_gc_likely_to_collect_more = false; 985 size_t committed_memory_before = 0; 986 987 if (collector == MARK_COMPACTOR) { 988 committed_memory_before = CommittedOldGenerationMemory(); 989 } 990 991 { 992 tracer()->Start(collector, gc_reason, collector_reason); 993 DCHECK(AllowHeapAllocation::IsAllowed()); 994 DisallowHeapAllocation no_allocation_during_gc; 995 GarbageCollectionPrologue(); 996 997 { 998 HistogramTimer* gc_type_timer = GCTypeTimer(collector); 999 HistogramTimerScope histogram_timer_scope(gc_type_timer); 1000 TRACE_EVENT0("v8", gc_type_timer->name()); 1001 1002 next_gc_likely_to_collect_more = 1003 PerformGarbageCollection(collector, gc_callback_flags); 1004 } 1005 1006 GarbageCollectionEpilogue(); 1007 if (collector == MARK_COMPACTOR && FLAG_track_detached_contexts) { 1008 isolate()->CheckDetachedContextsAfterGC(); 1009 } 1010 1011 if (collector == MARK_COMPACTOR) { 1012 size_t committed_memory_after = CommittedOldGenerationMemory(); 1013 size_t used_memory_after = PromotedSpaceSizeOfObjects(); 1014 MemoryReducer::Event event; 1015 event.type = MemoryReducer::kMarkCompact; 1016 event.time_ms = MonotonicallyIncreasingTimeInMs(); 1017 // Trigger one more GC if 1018 // - this GC decreased committed memory, 1019 // - there is high fragmentation, 1020 // - there are live detached contexts. 1021 event.next_gc_likely_to_collect_more = 1022 (committed_memory_before > committed_memory_after + MB) || 1023 HasHighFragmentation(used_memory_after, committed_memory_after) || 1024 (detached_contexts()->length() > 0); 1025 if (deserialization_complete_) { 1026 memory_reducer_->NotifyMarkCompact(event); 1027 } 1028 memory_pressure_level_.SetValue(MemoryPressureLevel::kNone); 1029 } 1030 1031 tracer()->Stop(collector); 1032 } 1033 1034 if (collector == MARK_COMPACTOR && 1035 (gc_callback_flags & (kGCCallbackFlagForced | 1036 kGCCallbackFlagCollectAllAvailableGarbage)) != 0) { 1037 isolate()->CountUsage(v8::Isolate::kForcedGC); 1038 } 1039 1040 // Start incremental marking for the next cycle. The heap snapshot 1041 // generator needs incremental marking to stay off after it aborted. 1042 // We do this only for scavenger to avoid a loop where mark-compact 1043 // causes another mark-compact. 1044 if (IsYoungGenerationCollector(collector) && 1045 !ShouldAbortIncrementalMarking()) { 1046 StartIncrementalMarkingIfAllocationLimitIsReached(kNoGCFlags, 1047 kNoGCCallbackFlags); 1048 } 1049 1050 return next_gc_likely_to_collect_more; 1051 } 1052 1053 1054 int Heap::NotifyContextDisposed(bool dependant_context) { 1055 if (!dependant_context) { 1056 tracer()->ResetSurvivalEvents(); 1057 old_generation_size_configured_ = false; 1058 MemoryReducer::Event event; 1059 event.type = MemoryReducer::kPossibleGarbage; 1060 event.time_ms = MonotonicallyIncreasingTimeInMs(); 1061 memory_reducer_->NotifyPossibleGarbage(event); 1062 } 1063 if (isolate()->concurrent_recompilation_enabled()) { 1064 // Flush the queued recompilation tasks. 1065 isolate()->optimizing_compile_dispatcher()->Flush( 1066 OptimizingCompileDispatcher::BlockingBehavior::kDontBlock); 1067 } 1068 AgeInlineCaches(); 1069 number_of_disposed_maps_ = retained_maps()->Length(); 1070 tracer()->AddContextDisposalTime(MonotonicallyIncreasingTimeInMs()); 1071 return ++contexts_disposed_; 1072 } 1073 1074 void Heap::StartIncrementalMarking(int gc_flags, 1075 GarbageCollectionReason gc_reason, 1076 GCCallbackFlags gc_callback_flags) { 1077 DCHECK(incremental_marking()->IsStopped()); 1078 set_current_gc_flags(gc_flags); 1079 current_gc_callback_flags_ = gc_callback_flags; 1080 incremental_marking()->Start(gc_reason); 1081 } 1082 1083 void Heap::StartIncrementalMarkingIfAllocationLimitIsReached( 1084 int gc_flags, const GCCallbackFlags gc_callback_flags) { 1085 if (incremental_marking()->IsStopped()) { 1086 IncrementalMarkingLimit reached_limit = IncrementalMarkingLimitReached(); 1087 if (reached_limit == IncrementalMarkingLimit::kSoftLimit) { 1088 incremental_marking()->incremental_marking_job()->ScheduleTask(this); 1089 } else if (reached_limit == IncrementalMarkingLimit::kHardLimit) { 1090 StartIncrementalMarking(gc_flags, 1091 GarbageCollectionReason::kAllocationLimit, 1092 gc_callback_flags); 1093 } 1094 } 1095 } 1096 1097 void Heap::StartIdleIncrementalMarking(GarbageCollectionReason gc_reason) { 1098 gc_idle_time_handler_->ResetNoProgressCounter(); 1099 StartIncrementalMarking(kReduceMemoryFootprintMask, gc_reason, 1100 kNoGCCallbackFlags); 1101 } 1102 1103 1104 void Heap::MoveElements(FixedArray* array, int dst_index, int src_index, 1105 int len) { 1106 if (len == 0) return; 1107 1108 DCHECK(array->map() != fixed_cow_array_map()); 1109 Object** dst_objects = array->data_start() + dst_index; 1110 MemMove(dst_objects, array->data_start() + src_index, len * kPointerSize); 1111 FIXED_ARRAY_ELEMENTS_WRITE_BARRIER(this, array, dst_index, len); 1112 } 1113 1114 1115 #ifdef VERIFY_HEAP 1116 // Helper class for verifying the string table. 1117 class StringTableVerifier : public ObjectVisitor { 1118 public: 1119 void VisitPointers(Object** start, Object** end) override { 1120 // Visit all HeapObject pointers in [start, end). 1121 for (Object** p = start; p < end; p++) { 1122 if ((*p)->IsHeapObject()) { 1123 HeapObject* object = HeapObject::cast(*p); 1124 Isolate* isolate = object->GetIsolate(); 1125 // Check that the string is actually internalized. 1126 CHECK(object->IsTheHole(isolate) || object->IsUndefined(isolate) || 1127 object->IsInternalizedString()); 1128 } 1129 } 1130 } 1131 }; 1132 1133 1134 static void VerifyStringTable(Heap* heap) { 1135 StringTableVerifier verifier; 1136 heap->string_table()->IterateElements(&verifier); 1137 } 1138 #endif // VERIFY_HEAP 1139 1140 bool Heap::ReserveSpace(Reservation* reservations, List<Address>* maps) { 1141 bool gc_performed = true; 1142 int counter = 0; 1143 static const int kThreshold = 20; 1144 while (gc_performed && counter++ < kThreshold) { 1145 gc_performed = false; 1146 for (int space = NEW_SPACE; space < SerializerDeserializer::kNumberOfSpaces; 1147 space++) { 1148 Reservation* reservation = &reservations[space]; 1149 DCHECK_LE(1, reservation->length()); 1150 if (reservation->at(0).size == 0) continue; 1151 bool perform_gc = false; 1152 if (space == MAP_SPACE) { 1153 // We allocate each map individually to avoid fragmentation. 1154 maps->Clear(); 1155 DCHECK_EQ(1, reservation->length()); 1156 int num_maps = reservation->at(0).size / Map::kSize; 1157 for (int i = 0; i < num_maps; i++) { 1158 // The deserializer will update the skip list. 1159 AllocationResult allocation = map_space()->AllocateRawUnaligned( 1160 Map::kSize, PagedSpace::IGNORE_SKIP_LIST); 1161 HeapObject* free_space = nullptr; 1162 if (allocation.To(&free_space)) { 1163 // Mark with a free list node, in case we have a GC before 1164 // deserializing. 1165 Address free_space_address = free_space->address(); 1166 CreateFillerObjectAt(free_space_address, Map::kSize, 1167 ClearRecordedSlots::kNo, ClearBlackArea::kNo); 1168 maps->Add(free_space_address); 1169 } else { 1170 perform_gc = true; 1171 break; 1172 } 1173 } 1174 } else if (space == LO_SPACE) { 1175 // Just check that we can allocate during deserialization. 1176 DCHECK_EQ(1, reservation->length()); 1177 perform_gc = !CanExpandOldGeneration(reservation->at(0).size); 1178 } else { 1179 for (auto& chunk : *reservation) { 1180 AllocationResult allocation; 1181 int size = chunk.size; 1182 DCHECK_LE(static_cast<size_t>(size), 1183 MemoryAllocator::PageAreaSize( 1184 static_cast<AllocationSpace>(space))); 1185 if (space == NEW_SPACE) { 1186 allocation = new_space()->AllocateRawUnaligned(size); 1187 } else { 1188 // The deserializer will update the skip list. 1189 allocation = paged_space(space)->AllocateRawUnaligned( 1190 size, PagedSpace::IGNORE_SKIP_LIST); 1191 } 1192 HeapObject* free_space = nullptr; 1193 if (allocation.To(&free_space)) { 1194 // Mark with a free list node, in case we have a GC before 1195 // deserializing. 1196 Address free_space_address = free_space->address(); 1197 CreateFillerObjectAt(free_space_address, size, 1198 ClearRecordedSlots::kNo, ClearBlackArea::kNo); 1199 DCHECK(space < SerializerDeserializer::kNumberOfPreallocatedSpaces); 1200 chunk.start = free_space_address; 1201 chunk.end = free_space_address + size; 1202 } else { 1203 perform_gc = true; 1204 break; 1205 } 1206 } 1207 } 1208 if (perform_gc) { 1209 if (space == NEW_SPACE) { 1210 CollectGarbage(NEW_SPACE, GarbageCollectionReason::kDeserializer); 1211 } else { 1212 if (counter > 1) { 1213 CollectAllGarbage( 1214 kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, 1215 GarbageCollectionReason::kDeserializer); 1216 } else { 1217 CollectAllGarbage(kAbortIncrementalMarkingMask, 1218 GarbageCollectionReason::kDeserializer); 1219 } 1220 } 1221 gc_performed = true; 1222 break; // Abort for-loop over spaces and retry. 1223 } 1224 } 1225 } 1226 1227 return !gc_performed; 1228 } 1229 1230 1231 void Heap::EnsureFromSpaceIsCommitted() { 1232 if (new_space_->CommitFromSpaceIfNeeded()) return; 1233 1234 // Committing memory to from space failed. 1235 // Memory is exhausted and we will die. 1236 V8::FatalProcessOutOfMemory("Committing semi space failed."); 1237 } 1238 1239 1240 void Heap::ClearNormalizedMapCaches() { 1241 if (isolate_->bootstrapper()->IsActive() && 1242 !incremental_marking()->IsMarking()) { 1243 return; 1244 } 1245 1246 Object* context = native_contexts_list(); 1247 while (!context->IsUndefined(isolate())) { 1248 // GC can happen when the context is not fully initialized, 1249 // so the cache can be undefined. 1250 Object* cache = 1251 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX); 1252 if (!cache->IsUndefined(isolate())) { 1253 NormalizedMapCache::cast(cache)->Clear(); 1254 } 1255 context = Context::cast(context)->next_context_link(); 1256 } 1257 } 1258 1259 1260 void Heap::UpdateSurvivalStatistics(int start_new_space_size) { 1261 if (start_new_space_size == 0) return; 1262 1263 promotion_ratio_ = (static_cast<double>(promoted_objects_size_) / 1264 static_cast<double>(start_new_space_size) * 100); 1265 1266 if (previous_semi_space_copied_object_size_ > 0) { 1267 promotion_rate_ = 1268 (static_cast<double>(promoted_objects_size_) / 1269 static_cast<double>(previous_semi_space_copied_object_size_) * 100); 1270 } else { 1271 promotion_rate_ = 0; 1272 } 1273 1274 semi_space_copied_rate_ = 1275 (static_cast<double>(semi_space_copied_object_size_) / 1276 static_cast<double>(start_new_space_size) * 100); 1277 1278 double survival_rate = promotion_ratio_ + semi_space_copied_rate_; 1279 tracer()->AddSurvivalRatio(survival_rate); 1280 } 1281 1282 bool Heap::PerformGarbageCollection( 1283 GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) { 1284 int freed_global_handles = 0; 1285 1286 if (!IsYoungGenerationCollector(collector)) { 1287 PROFILE(isolate_, CodeMovingGCEvent()); 1288 } 1289 1290 #ifdef VERIFY_HEAP 1291 if (FLAG_verify_heap) { 1292 VerifyStringTable(this); 1293 } 1294 #endif 1295 1296 GCType gc_type = 1297 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge; 1298 1299 { 1300 GCCallbacksScope scope(this); 1301 if (scope.CheckReenter()) { 1302 AllowHeapAllocation allow_allocation; 1303 TRACE_GC(tracer(), GCTracer::Scope::EXTERNAL_PROLOGUE); 1304 VMState<EXTERNAL> state(isolate_); 1305 HandleScope handle_scope(isolate_); 1306 CallGCPrologueCallbacks(gc_type, kNoGCCallbackFlags); 1307 } 1308 } 1309 1310 EnsureFromSpaceIsCommitted(); 1311 1312 int start_new_space_size = static_cast<int>(Heap::new_space()->Size()); 1313 1314 { 1315 Heap::PretenuringScope pretenuring_scope(this); 1316 1317 switch (collector) { 1318 case MARK_COMPACTOR: 1319 UpdateOldGenerationAllocationCounter(); 1320 // Perform mark-sweep with optional compaction. 1321 MarkCompact(); 1322 old_generation_size_configured_ = true; 1323 // This should be updated before PostGarbageCollectionProcessing, which 1324 // can cause another GC. Take into account the objects promoted during 1325 // GC. 1326 old_generation_allocation_counter_at_last_gc_ += 1327 static_cast<size_t>(promoted_objects_size_); 1328 old_generation_size_at_last_gc_ = PromotedSpaceSizeOfObjects(); 1329 break; 1330 case MINOR_MARK_COMPACTOR: 1331 MinorMarkCompact(); 1332 break; 1333 case SCAVENGER: 1334 Scavenge(); 1335 break; 1336 } 1337 1338 ProcessPretenuringFeedback(); 1339 } 1340 1341 UpdateSurvivalStatistics(start_new_space_size); 1342 ConfigureInitialOldGenerationSize(); 1343 1344 isolate_->counters()->objs_since_last_young()->Set(0); 1345 1346 gc_post_processing_depth_++; 1347 { 1348 AllowHeapAllocation allow_allocation; 1349 TRACE_GC(tracer(), GCTracer::Scope::EXTERNAL_WEAK_GLOBAL_HANDLES); 1350 freed_global_handles = 1351 isolate_->global_handles()->PostGarbageCollectionProcessing( 1352 collector, gc_callback_flags); 1353 } 1354 gc_post_processing_depth_--; 1355 1356 isolate_->eternal_handles()->PostGarbageCollectionProcessing(this); 1357 1358 // Update relocatables. 1359 Relocatable::PostGarbageCollectionProcessing(isolate_); 1360 1361 double gc_speed = tracer()->CombinedMarkCompactSpeedInBytesPerMillisecond(); 1362 double mutator_speed = 1363 tracer()->CurrentOldGenerationAllocationThroughputInBytesPerMillisecond(); 1364 size_t old_gen_size = PromotedSpaceSizeOfObjects(); 1365 if (collector == MARK_COMPACTOR) { 1366 // Register the amount of external allocated memory. 1367 external_memory_at_last_mark_compact_ = external_memory_; 1368 external_memory_limit_ = external_memory_ + kExternalAllocationSoftLimit; 1369 SetOldGenerationAllocationLimit(old_gen_size, gc_speed, mutator_speed); 1370 } else if (HasLowYoungGenerationAllocationRate() && 1371 old_generation_size_configured_) { 1372 DampenOldGenerationAllocationLimit(old_gen_size, gc_speed, mutator_speed); 1373 } 1374 1375 { 1376 GCCallbacksScope scope(this); 1377 if (scope.CheckReenter()) { 1378 AllowHeapAllocation allow_allocation; 1379 TRACE_GC(tracer(), GCTracer::Scope::EXTERNAL_EPILOGUE); 1380 VMState<EXTERNAL> state(isolate_); 1381 HandleScope handle_scope(isolate_); 1382 CallGCEpilogueCallbacks(gc_type, gc_callback_flags); 1383 } 1384 } 1385 1386 #ifdef VERIFY_HEAP 1387 if (FLAG_verify_heap) { 1388 VerifyStringTable(this); 1389 } 1390 #endif 1391 1392 return freed_global_handles > 0; 1393 } 1394 1395 1396 void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) { 1397 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { 1398 if (gc_type & gc_prologue_callbacks_[i].gc_type) { 1399 if (!gc_prologue_callbacks_[i].pass_isolate) { 1400 v8::GCCallback callback = reinterpret_cast<v8::GCCallback>( 1401 gc_prologue_callbacks_[i].callback); 1402 callback(gc_type, flags); 1403 } else { 1404 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate()); 1405 gc_prologue_callbacks_[i].callback(isolate, gc_type, flags); 1406 } 1407 } 1408 } 1409 if (FLAG_trace_object_groups && (gc_type == kGCTypeIncrementalMarking || 1410 gc_type == kGCTypeMarkSweepCompact)) { 1411 isolate_->global_handles()->PrintObjectGroups(); 1412 } 1413 } 1414 1415 1416 void Heap::CallGCEpilogueCallbacks(GCType gc_type, 1417 GCCallbackFlags gc_callback_flags) { 1418 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) { 1419 if (gc_type & gc_epilogue_callbacks_[i].gc_type) { 1420 if (!gc_epilogue_callbacks_[i].pass_isolate) { 1421 v8::GCCallback callback = reinterpret_cast<v8::GCCallback>( 1422 gc_epilogue_callbacks_[i].callback); 1423 callback(gc_type, gc_callback_flags); 1424 } else { 1425 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate()); 1426 gc_epilogue_callbacks_[i].callback(isolate, gc_type, gc_callback_flags); 1427 } 1428 } 1429 } 1430 } 1431 1432 1433 void Heap::MarkCompact() { 1434 PauseAllocationObserversScope pause_observers(this); 1435 1436 gc_state_ = MARK_COMPACT; 1437 LOG(isolate_, ResourceEvent("markcompact", "begin")); 1438 1439 uint64_t size_of_objects_before_gc = SizeOfObjects(); 1440 1441 mark_compact_collector()->Prepare(); 1442 1443 ms_count_++; 1444 1445 MarkCompactPrologue(); 1446 1447 mark_compact_collector()->CollectGarbage(); 1448 1449 LOG(isolate_, ResourceEvent("markcompact", "end")); 1450 1451 MarkCompactEpilogue(); 1452 1453 if (FLAG_allocation_site_pretenuring) { 1454 EvaluateOldSpaceLocalPretenuring(size_of_objects_before_gc); 1455 } 1456 } 1457 1458 void Heap::MinorMarkCompact() { UNREACHABLE(); } 1459 1460 void Heap::MarkCompactEpilogue() { 1461 TRACE_GC(tracer(), GCTracer::Scope::MC_EPILOGUE); 1462 gc_state_ = NOT_IN_GC; 1463 1464 isolate_->counters()->objs_since_last_full()->Set(0); 1465 1466 incremental_marking()->Epilogue(); 1467 1468 PreprocessStackTraces(); 1469 DCHECK(incremental_marking()->IsStopped()); 1470 1471 mark_compact_collector()->marking_deque()->StopUsing(); 1472 } 1473 1474 1475 void Heap::MarkCompactPrologue() { 1476 TRACE_GC(tracer(), GCTracer::Scope::MC_PROLOGUE); 1477 isolate_->context_slot_cache()->Clear(); 1478 isolate_->descriptor_lookup_cache()->Clear(); 1479 RegExpResultsCache::Clear(string_split_cache()); 1480 RegExpResultsCache::Clear(regexp_multiple_cache()); 1481 1482 isolate_->compilation_cache()->MarkCompactPrologue(); 1483 1484 CompletelyClearInstanceofCache(); 1485 1486 FlushNumberStringCache(); 1487 ClearNormalizedMapCaches(); 1488 } 1489 1490 1491 void Heap::CheckNewSpaceExpansionCriteria() { 1492 if (FLAG_experimental_new_space_growth_heuristic) { 1493 if (new_space_->TotalCapacity() < new_space_->MaximumCapacity() && 1494 survived_last_scavenge_ * 100 / new_space_->TotalCapacity() >= 10) { 1495 // Grow the size of new space if there is room to grow, and more than 10% 1496 // have survived the last scavenge. 1497 new_space_->Grow(); 1498 survived_since_last_expansion_ = 0; 1499 } 1500 } else if (new_space_->TotalCapacity() < new_space_->MaximumCapacity() && 1501 survived_since_last_expansion_ > new_space_->TotalCapacity()) { 1502 // Grow the size of new space if there is room to grow, and enough data 1503 // has survived scavenge since the last expansion. 1504 new_space_->Grow(); 1505 survived_since_last_expansion_ = 0; 1506 } 1507 } 1508 1509 1510 static bool IsUnscavengedHeapObject(Heap* heap, Object** p) { 1511 return heap->InNewSpace(*p) && 1512 !HeapObject::cast(*p)->map_word().IsForwardingAddress(); 1513 } 1514 1515 1516 static bool IsUnmodifiedHeapObject(Object** p) { 1517 Object* object = *p; 1518 if (object->IsSmi()) return false; 1519 HeapObject* heap_object = HeapObject::cast(object); 1520 if (!object->IsJSObject()) return false; 1521 JSObject* js_object = JSObject::cast(object); 1522 if (!js_object->WasConstructedFromApiFunction()) return false; 1523 JSFunction* constructor = 1524 JSFunction::cast(js_object->map()->GetConstructor()); 1525 1526 return constructor->initial_map() == heap_object->map(); 1527 } 1528 1529 1530 void PromotionQueue::Initialize() { 1531 // The last to-space page may be used for promotion queue. On promotion 1532 // conflict, we use the emergency stack. 1533 DCHECK((Page::kPageSize - MemoryChunk::kBodyOffset) % (2 * kPointerSize) == 1534 0); 1535 front_ = rear_ = 1536 reinterpret_cast<struct Entry*>(heap_->new_space()->ToSpaceEnd()); 1537 limit_ = reinterpret_cast<struct Entry*>( 1538 Page::FromAllocationAreaAddress(reinterpret_cast<Address>(rear_)) 1539 ->area_start()); 1540 emergency_stack_ = NULL; 1541 } 1542 1543 void PromotionQueue::Destroy() { 1544 DCHECK(is_empty()); 1545 delete emergency_stack_; 1546 emergency_stack_ = NULL; 1547 } 1548 1549 void PromotionQueue::RelocateQueueHead() { 1550 DCHECK(emergency_stack_ == NULL); 1551 1552 Page* p = Page::FromAllocationAreaAddress(reinterpret_cast<Address>(rear_)); 1553 struct Entry* head_start = rear_; 1554 struct Entry* head_end = 1555 Min(front_, reinterpret_cast<struct Entry*>(p->area_end())); 1556 1557 int entries_count = 1558 static_cast<int>(head_end - head_start) / sizeof(struct Entry); 1559 1560 emergency_stack_ = new List<Entry>(2 * entries_count); 1561 1562 while (head_start != head_end) { 1563 struct Entry* entry = head_start++; 1564 // New space allocation in SemiSpaceCopyObject marked the region 1565 // overlapping with promotion queue as uninitialized. 1566 MSAN_MEMORY_IS_INITIALIZED(entry, sizeof(struct Entry)); 1567 emergency_stack_->Add(*entry); 1568 } 1569 rear_ = head_end; 1570 } 1571 1572 1573 class ScavengeWeakObjectRetainer : public WeakObjectRetainer { 1574 public: 1575 explicit ScavengeWeakObjectRetainer(Heap* heap) : heap_(heap) {} 1576 1577 virtual Object* RetainAs(Object* object) { 1578 if (!heap_->InFromSpace(object)) { 1579 return object; 1580 } 1581 1582 MapWord map_word = HeapObject::cast(object)->map_word(); 1583 if (map_word.IsForwardingAddress()) { 1584 return map_word.ToForwardingAddress(); 1585 } 1586 return NULL; 1587 } 1588 1589 private: 1590 Heap* heap_; 1591 }; 1592 1593 1594 void Heap::Scavenge() { 1595 TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE); 1596 RelocationLock relocation_lock(this); 1597 // There are soft limits in the allocation code, designed to trigger a mark 1598 // sweep collection by failing allocations. There is no sense in trying to 1599 // trigger one during scavenge: scavenges allocation should always succeed. 1600 AlwaysAllocateScope scope(isolate()); 1601 1602 // Bump-pointer allocations done during scavenge are not real allocations. 1603 // Pause the inline allocation steps. 1604 PauseAllocationObserversScope pause_observers(this); 1605 1606 mark_compact_collector()->sweeper().EnsureNewSpaceCompleted(); 1607 1608 gc_state_ = SCAVENGE; 1609 1610 // Implements Cheney's copying algorithm 1611 LOG(isolate_, ResourceEvent("scavenge", "begin")); 1612 1613 // Used for updating survived_since_last_expansion_ at function end. 1614 size_t survived_watermark = PromotedSpaceSizeOfObjects(); 1615 1616 scavenge_collector_->SelectScavengingVisitorsTable(); 1617 1618 if (UsingEmbedderHeapTracer()) { 1619 // Register found wrappers with embedder so it can add them to its marking 1620 // deque and correctly manage the case when v8 scavenger collects the 1621 // wrappers by either keeping wrappables alive, or cleaning marking deque. 1622 RegisterWrappersWithEmbedderHeapTracer(); 1623 } 1624 1625 // Flip the semispaces. After flipping, to space is empty, from space has 1626 // live objects. 1627 new_space_->Flip(); 1628 new_space_->ResetAllocationInfo(); 1629 1630 // We need to sweep newly copied objects which can be either in the 1631 // to space or promoted to the old generation. For to-space 1632 // objects, we treat the bottom of the to space as a queue. Newly 1633 // copied and unswept objects lie between a 'front' mark and the 1634 // allocation pointer. 1635 // 1636 // Promoted objects can go into various old-generation spaces, and 1637 // can be allocated internally in the spaces (from the free list). 1638 // We treat the top of the to space as a queue of addresses of 1639 // promoted objects. The addresses of newly promoted and unswept 1640 // objects lie between a 'front' mark and a 'rear' mark that is 1641 // updated as a side effect of promoting an object. 1642 // 1643 // There is guaranteed to be enough room at the top of the to space 1644 // for the addresses of promoted objects: every object promoted 1645 // frees up its size in bytes from the top of the new space, and 1646 // objects are at least one pointer in size. 1647 Address new_space_front = new_space_->ToSpaceStart(); 1648 promotion_queue_.Initialize(); 1649 1650 ScavengeVisitor scavenge_visitor(this); 1651 1652 isolate()->global_handles()->IdentifyWeakUnmodifiedObjects( 1653 &IsUnmodifiedHeapObject); 1654 1655 { 1656 // Copy roots. 1657 TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_ROOTS); 1658 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE); 1659 } 1660 1661 { 1662 // Copy objects reachable from the old generation. 1663 TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_OLD_TO_NEW_POINTERS); 1664 RememberedSet<OLD_TO_NEW>::Iterate(this, [this](Address addr) { 1665 return Scavenger::CheckAndScavengeObject(this, addr); 1666 }); 1667 1668 RememberedSet<OLD_TO_NEW>::IterateTyped( 1669 this, [this](SlotType type, Address host_addr, Address addr) { 1670 return UpdateTypedSlotHelper::UpdateTypedSlot( 1671 isolate(), type, addr, [this](Object** addr) { 1672 // We expect that objects referenced by code are long living. 1673 // If we do not force promotion, then we need to clear 1674 // old_to_new slots in dead code objects after mark-compact. 1675 return Scavenger::CheckAndScavengeObject( 1676 this, reinterpret_cast<Address>(addr)); 1677 }); 1678 }); 1679 } 1680 1681 { 1682 TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_WEAK); 1683 // Copy objects reachable from the encountered weak collections list. 1684 scavenge_visitor.VisitPointer(&encountered_weak_collections_); 1685 } 1686 1687 { 1688 // Copy objects reachable from the code flushing candidates list. 1689 TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_CODE_FLUSH_CANDIDATES); 1690 MarkCompactCollector* collector = mark_compact_collector(); 1691 if (collector->is_code_flushing_enabled()) { 1692 collector->code_flusher()->IteratePointersToFromSpace(&scavenge_visitor); 1693 } 1694 } 1695 1696 { 1697 TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_SEMISPACE); 1698 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); 1699 } 1700 1701 isolate()->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending( 1702 &IsUnscavengedHeapObject); 1703 1704 isolate()->global_handles()->IterateNewSpaceWeakUnmodifiedRoots( 1705 &scavenge_visitor); 1706 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); 1707 1708 UpdateNewSpaceReferencesInExternalStringTable( 1709 &UpdateNewSpaceReferenceInExternalStringTableEntry); 1710 1711 promotion_queue_.Destroy(); 1712 1713 incremental_marking()->UpdateMarkingDequeAfterScavenge(); 1714 1715 ScavengeWeakObjectRetainer weak_object_retainer(this); 1716 ProcessYoungWeakReferences(&weak_object_retainer); 1717 1718 DCHECK(new_space_front == new_space_->top()); 1719 1720 // Set age mark. 1721 new_space_->set_age_mark(new_space_->top()); 1722 1723 ArrayBufferTracker::FreeDeadInNewSpace(this); 1724 1725 // Update how much has survived scavenge. 1726 DCHECK_GE(PromotedSpaceSizeOfObjects(), survived_watermark); 1727 IncrementYoungSurvivorsCounter(PromotedSpaceSizeOfObjects() + 1728 new_space_->Size() - survived_watermark); 1729 1730 LOG(isolate_, ResourceEvent("scavenge", "end")); 1731 1732 gc_state_ = NOT_IN_GC; 1733 } 1734 1735 1736 String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, 1737 Object** p) { 1738 MapWord first_word = HeapObject::cast(*p)->map_word(); 1739 1740 if (!first_word.IsForwardingAddress()) { 1741 // Unreachable external string can be finalized. 1742 heap->FinalizeExternalString(String::cast(*p)); 1743 return NULL; 1744 } 1745 1746 // String is still reachable. 1747 return String::cast(first_word.ToForwardingAddress()); 1748 } 1749 1750 1751 void Heap::UpdateNewSpaceReferencesInExternalStringTable( 1752 ExternalStringTableUpdaterCallback updater_func) { 1753 if (external_string_table_.new_space_strings_.is_empty()) return; 1754 1755 Object** start = &external_string_table_.new_space_strings_[0]; 1756 Object** end = start + external_string_table_.new_space_strings_.length(); 1757 Object** last = start; 1758 1759 for (Object** p = start; p < end; ++p) { 1760 String* target = updater_func(this, p); 1761 1762 if (target == NULL) continue; 1763 1764 DCHECK(target->IsExternalString()); 1765 1766 if (InNewSpace(target)) { 1767 // String is still in new space. Update the table entry. 1768 *last = target; 1769 ++last; 1770 } else { 1771 // String got promoted. Move it to the old string list. 1772 external_string_table_.AddOldString(target); 1773 } 1774 } 1775 1776 DCHECK(last <= end); 1777 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start)); 1778 } 1779 1780 1781 void Heap::UpdateReferencesInExternalStringTable( 1782 ExternalStringTableUpdaterCallback updater_func) { 1783 // Update old space string references. 1784 if (external_string_table_.old_space_strings_.length() > 0) { 1785 Object** start = &external_string_table_.old_space_strings_[0]; 1786 Object** end = start + external_string_table_.old_space_strings_.length(); 1787 for (Object** p = start; p < end; ++p) *p = updater_func(this, p); 1788 } 1789 1790 UpdateNewSpaceReferencesInExternalStringTable(updater_func); 1791 } 1792 1793 1794 void Heap::ProcessAllWeakReferences(WeakObjectRetainer* retainer) { 1795 ProcessNativeContexts(retainer); 1796 ProcessAllocationSites(retainer); 1797 } 1798 1799 1800 void Heap::ProcessYoungWeakReferences(WeakObjectRetainer* retainer) { 1801 ProcessNativeContexts(retainer); 1802 } 1803 1804 1805 void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer) { 1806 Object* head = VisitWeakList<Context>(this, native_contexts_list(), retainer); 1807 // Update the head of the list of contexts. 1808 set_native_contexts_list(head); 1809 } 1810 1811 1812 void Heap::ProcessAllocationSites(WeakObjectRetainer* retainer) { 1813 Object* allocation_site_obj = 1814 VisitWeakList<AllocationSite>(this, allocation_sites_list(), retainer); 1815 set_allocation_sites_list(allocation_site_obj); 1816 } 1817 1818 void Heap::ProcessWeakListRoots(WeakObjectRetainer* retainer) { 1819 set_native_contexts_list(retainer->RetainAs(native_contexts_list())); 1820 set_allocation_sites_list(retainer->RetainAs(allocation_sites_list())); 1821 } 1822 1823 void Heap::ResetAllAllocationSitesDependentCode(PretenureFlag flag) { 1824 DisallowHeapAllocation no_allocation_scope; 1825 Object* cur = allocation_sites_list(); 1826 bool marked = false; 1827 while (cur->IsAllocationSite()) { 1828 AllocationSite* casted = AllocationSite::cast(cur); 1829 if (casted->GetPretenureMode() == flag) { 1830 casted->ResetPretenureDecision(); 1831 casted->set_deopt_dependent_code(true); 1832 marked = true; 1833 RemoveAllocationSitePretenuringFeedback(casted); 1834 } 1835 cur = casted->weak_next(); 1836 } 1837 if (marked) isolate_->stack_guard()->RequestDeoptMarkedAllocationSites(); 1838 } 1839 1840 1841 void Heap::EvaluateOldSpaceLocalPretenuring( 1842 uint64_t size_of_objects_before_gc) { 1843 uint64_t size_of_objects_after_gc = SizeOfObjects(); 1844 double old_generation_survival_rate = 1845 (static_cast<double>(size_of_objects_after_gc) * 100) / 1846 static_cast<double>(size_of_objects_before_gc); 1847 1848 if (old_generation_survival_rate < kOldSurvivalRateLowThreshold) { 1849 // Too many objects died in the old generation, pretenuring of wrong 1850 // allocation sites may be the cause for that. We have to deopt all 1851 // dependent code registered in the allocation sites to re-evaluate 1852 // our pretenuring decisions. 1853 ResetAllAllocationSitesDependentCode(TENURED); 1854 if (FLAG_trace_pretenuring) { 1855 PrintF( 1856 "Deopt all allocation sites dependent code due to low survival " 1857 "rate in the old generation %f\n", 1858 old_generation_survival_rate); 1859 } 1860 } 1861 } 1862 1863 1864 void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) { 1865 DisallowHeapAllocation no_allocation; 1866 // All external strings are listed in the external string table. 1867 1868 class ExternalStringTableVisitorAdapter : public ObjectVisitor { 1869 public: 1870 explicit ExternalStringTableVisitorAdapter( 1871 v8::ExternalResourceVisitor* visitor) 1872 : visitor_(visitor) {} 1873 virtual void VisitPointers(Object** start, Object** end) { 1874 for (Object** p = start; p < end; p++) { 1875 DCHECK((*p)->IsExternalString()); 1876 visitor_->VisitExternalString( 1877 Utils::ToLocal(Handle<String>(String::cast(*p)))); 1878 } 1879 } 1880 1881 private: 1882 v8::ExternalResourceVisitor* visitor_; 1883 } external_string_table_visitor(visitor); 1884 1885 external_string_table_.Iterate(&external_string_table_visitor); 1886 } 1887 1888 Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, 1889 Address new_space_front) { 1890 do { 1891 SemiSpace::AssertValidRange(new_space_front, new_space_->top()); 1892 // The addresses new_space_front and new_space_.top() define a 1893 // queue of unprocessed copied objects. Process them until the 1894 // queue is empty. 1895 while (new_space_front != new_space_->top()) { 1896 if (!Page::IsAlignedToPageSize(new_space_front)) { 1897 HeapObject* object = HeapObject::FromAddress(new_space_front); 1898 new_space_front += 1899 StaticScavengeVisitor::IterateBody(object->map(), object); 1900 } else { 1901 new_space_front = Page::FromAllocationAreaAddress(new_space_front) 1902 ->next_page() 1903 ->area_start(); 1904 } 1905 } 1906 1907 // Promote and process all the to-be-promoted objects. 1908 { 1909 while (!promotion_queue()->is_empty()) { 1910 HeapObject* target; 1911 int32_t size; 1912 bool was_marked_black; 1913 promotion_queue()->remove(&target, &size, &was_marked_black); 1914 1915 // Promoted object might be already partially visited 1916 // during old space pointer iteration. Thus we search specifically 1917 // for pointers to from semispace instead of looking for pointers 1918 // to new space. 1919 DCHECK(!target->IsMap()); 1920 1921 IterateAndScavengePromotedObject(target, static_cast<int>(size), 1922 was_marked_black); 1923 } 1924 } 1925 1926 // Take another spin if there are now unswept objects in new space 1927 // (there are currently no more unswept promoted objects). 1928 } while (new_space_front != new_space_->top()); 1929 1930 return new_space_front; 1931 } 1932 1933 1934 STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == 1935 0); // NOLINT 1936 STATIC_ASSERT((FixedTypedArrayBase::kDataOffset & kDoubleAlignmentMask) == 1937 0); // NOLINT 1938 #ifdef V8_HOST_ARCH_32_BIT 1939 STATIC_ASSERT((HeapNumber::kValueOffset & kDoubleAlignmentMask) != 1940 0); // NOLINT 1941 #endif 1942 1943 1944 int Heap::GetMaximumFillToAlign(AllocationAlignment alignment) { 1945 switch (alignment) { 1946 case kWordAligned: 1947 return 0; 1948 case kDoubleAligned: 1949 case kDoubleUnaligned: 1950 return kDoubleSize - kPointerSize; 1951 case kSimd128Unaligned: 1952 return kSimd128Size - kPointerSize; 1953 default: 1954 UNREACHABLE(); 1955 } 1956 return 0; 1957 } 1958 1959 1960 int Heap::GetFillToAlign(Address address, AllocationAlignment alignment) { 1961 intptr_t offset = OffsetFrom(address); 1962 if (alignment == kDoubleAligned && (offset & kDoubleAlignmentMask) != 0) 1963 return kPointerSize; 1964 if (alignment == kDoubleUnaligned && (offset & kDoubleAlignmentMask) == 0) 1965 return kDoubleSize - kPointerSize; // No fill if double is always aligned. 1966 if (alignment == kSimd128Unaligned) { 1967 return (kSimd128Size - (static_cast<int>(offset) + kPointerSize)) & 1968 kSimd128AlignmentMask; 1969 } 1970 return 0; 1971 } 1972 1973 1974 HeapObject* Heap::PrecedeWithFiller(HeapObject* object, int filler_size) { 1975 CreateFillerObjectAt(object->address(), filler_size, ClearRecordedSlots::kNo); 1976 return HeapObject::FromAddress(object->address() + filler_size); 1977 } 1978 1979 1980 HeapObject* Heap::AlignWithFiller(HeapObject* object, int object_size, 1981 int allocation_size, 1982 AllocationAlignment alignment) { 1983 int filler_size = allocation_size - object_size; 1984 DCHECK(filler_size > 0); 1985 int pre_filler = GetFillToAlign(object->address(), alignment); 1986 if (pre_filler) { 1987 object = PrecedeWithFiller(object, pre_filler); 1988 filler_size -= pre_filler; 1989 } 1990 if (filler_size) 1991 CreateFillerObjectAt(object->address() + object_size, filler_size, 1992 ClearRecordedSlots::kNo); 1993 return object; 1994 } 1995 1996 1997 HeapObject* Heap::DoubleAlignForDeserialization(HeapObject* object, int size) { 1998 return AlignWithFiller(object, size - kPointerSize, size, kDoubleAligned); 1999 } 2000 2001 2002 void Heap::RegisterNewArrayBuffer(JSArrayBuffer* buffer) { 2003 ArrayBufferTracker::RegisterNew(this, buffer); 2004 } 2005 2006 2007 void Heap::UnregisterArrayBuffer(JSArrayBuffer* buffer) { 2008 ArrayBufferTracker::Unregister(this, buffer); 2009 } 2010 2011 2012 void Heap::ConfigureInitialOldGenerationSize() { 2013 if (!old_generation_size_configured_ && tracer()->SurvivalEventsRecorded()) { 2014 old_generation_allocation_limit_ = 2015 Max(MinimumAllocationLimitGrowingStep(), 2016 static_cast<size_t>( 2017 static_cast<double>(old_generation_allocation_limit_) * 2018 (tracer()->AverageSurvivalRatio() / 100))); 2019 } 2020 } 2021 2022 2023 AllocationResult Heap::AllocatePartialMap(InstanceType instance_type, 2024 int instance_size) { 2025 Object* result = nullptr; 2026 AllocationResult allocation = AllocateRaw(Map::kSize, MAP_SPACE); 2027 if (!allocation.To(&result)) return allocation; 2028 2029 // Map::cast cannot be used due to uninitialized map field. 2030 reinterpret_cast<Map*>(result)->set_map( 2031 reinterpret_cast<Map*>(root(kMetaMapRootIndex))); 2032 reinterpret_cast<Map*>(result)->set_instance_type(instance_type); 2033 reinterpret_cast<Map*>(result)->set_instance_size(instance_size); 2034 // Initialize to only containing tagged fields. 2035 reinterpret_cast<Map*>(result)->set_visitor_id( 2036 StaticVisitorBase::GetVisitorId(instance_type, instance_size, false)); 2037 if (FLAG_unbox_double_fields) { 2038 reinterpret_cast<Map*>(result) 2039 ->set_layout_descriptor(LayoutDescriptor::FastPointerLayout()); 2040 } 2041 reinterpret_cast<Map*>(result)->clear_unused(); 2042 reinterpret_cast<Map*>(result) 2043 ->set_inobject_properties_or_constructor_function_index(0); 2044 reinterpret_cast<Map*>(result)->set_unused_property_fields(0); 2045 reinterpret_cast<Map*>(result)->set_bit_field(0); 2046 reinterpret_cast<Map*>(result)->set_bit_field2(0); 2047 int bit_field3 = Map::EnumLengthBits::encode(kInvalidEnumCacheSentinel) | 2048 Map::OwnsDescriptors::encode(true) | 2049 Map::ConstructionCounter::encode(Map::kNoSlackTracking); 2050 reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3); 2051 reinterpret_cast<Map*>(result)->set_weak_cell_cache(Smi::kZero); 2052 return result; 2053 } 2054 2055 2056 AllocationResult Heap::AllocateMap(InstanceType instance_type, 2057 int instance_size, 2058 ElementsKind elements_kind) { 2059 HeapObject* result = nullptr; 2060 AllocationResult allocation = AllocateRaw(Map::kSize, MAP_SPACE); 2061 if (!allocation.To(&result)) return allocation; 2062 2063 isolate()->counters()->maps_created()->Increment(); 2064 result->set_map_no_write_barrier(meta_map()); 2065 Map* map = Map::cast(result); 2066 map->set_instance_type(instance_type); 2067 map->set_prototype(null_value(), SKIP_WRITE_BARRIER); 2068 map->set_constructor_or_backpointer(null_value(), SKIP_WRITE_BARRIER); 2069 map->set_instance_size(instance_size); 2070 map->clear_unused(); 2071 map->set_inobject_properties_or_constructor_function_index(0); 2072 map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER); 2073 map->set_dependent_code(DependentCode::cast(empty_fixed_array()), 2074 SKIP_WRITE_BARRIER); 2075 map->set_weak_cell_cache(Smi::kZero); 2076 map->set_raw_transitions(Smi::kZero); 2077 map->set_unused_property_fields(0); 2078 map->set_instance_descriptors(empty_descriptor_array()); 2079 if (FLAG_unbox_double_fields) { 2080 map->set_layout_descriptor(LayoutDescriptor::FastPointerLayout()); 2081 } 2082 // Must be called only after |instance_type|, |instance_size| and 2083 // |layout_descriptor| are set. 2084 map->set_visitor_id(Heap::GetStaticVisitorIdForMap(map)); 2085 map->set_bit_field(0); 2086 map->set_bit_field2(1 << Map::kIsExtensible); 2087 int bit_field3 = Map::EnumLengthBits::encode(kInvalidEnumCacheSentinel) | 2088 Map::OwnsDescriptors::encode(true) | 2089 Map::ConstructionCounter::encode(Map::kNoSlackTracking); 2090 map->set_bit_field3(bit_field3); 2091 map->set_elements_kind(elements_kind); 2092 map->set_new_target_is_base(true); 2093 2094 return map; 2095 } 2096 2097 2098 AllocationResult Heap::AllocateFillerObject(int size, bool double_align, 2099 AllocationSpace space) { 2100 HeapObject* obj = nullptr; 2101 { 2102 AllocationAlignment align = double_align ? kDoubleAligned : kWordAligned; 2103 AllocationResult allocation = AllocateRaw(size, space, align); 2104 if (!allocation.To(&obj)) return allocation; 2105 } 2106 #ifdef DEBUG 2107 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); 2108 DCHECK(chunk->owner()->identity() == space); 2109 #endif 2110 CreateFillerObjectAt(obj->address(), size, ClearRecordedSlots::kNo, 2111 ClearBlackArea::kNo); 2112 return obj; 2113 } 2114 2115 2116 const Heap::StringTypeTable Heap::string_type_table[] = { 2117 #define STRING_TYPE_ELEMENT(type, size, name, camel_name) \ 2118 { type, size, k##camel_name##MapRootIndex } \ 2119 , 2120 STRING_TYPE_LIST(STRING_TYPE_ELEMENT) 2121 #undef STRING_TYPE_ELEMENT 2122 }; 2123 2124 2125 const Heap::ConstantStringTable Heap::constant_string_table[] = { 2126 {"", kempty_stringRootIndex}, 2127 #define CONSTANT_STRING_ELEMENT(name, contents) \ 2128 { contents, k##name##RootIndex } \ 2129 , 2130 INTERNALIZED_STRING_LIST(CONSTANT_STRING_ELEMENT) 2131 #undef CONSTANT_STRING_ELEMENT 2132 }; 2133 2134 2135 const Heap::StructTable Heap::struct_table[] = { 2136 #define STRUCT_TABLE_ELEMENT(NAME, Name, name) \ 2137 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex } \ 2138 , 2139 STRUCT_LIST(STRUCT_TABLE_ELEMENT) 2140 #undef STRUCT_TABLE_ELEMENT 2141 }; 2142 2143 namespace { 2144 2145 void FinalizePartialMap(Heap* heap, Map* map) { 2146 map->set_code_cache(heap->empty_fixed_array()); 2147 map->set_dependent_code(DependentCode::cast(heap->empty_fixed_array())); 2148 map->set_raw_transitions(Smi::kZero); 2149 map->set_instance_descriptors(heap->empty_descriptor_array()); 2150 if (FLAG_unbox_double_fields) { 2151 map->set_layout_descriptor(LayoutDescriptor::FastPointerLayout()); 2152 } 2153 map->set_prototype(heap->null_value()); 2154 map->set_constructor_or_backpointer(heap->null_value()); 2155 } 2156 2157 } // namespace 2158 2159 bool Heap::CreateInitialMaps() { 2160 HeapObject* obj = nullptr; 2161 { 2162 AllocationResult allocation = AllocatePartialMap(MAP_TYPE, Map::kSize); 2163 if (!allocation.To(&obj)) return false; 2164 } 2165 // Map::cast cannot be used due to uninitialized map field. 2166 Map* new_meta_map = reinterpret_cast<Map*>(obj); 2167 set_meta_map(new_meta_map); 2168 new_meta_map->set_map(new_meta_map); 2169 2170 { // Partial map allocation 2171 #define ALLOCATE_PARTIAL_MAP(instance_type, size, field_name) \ 2172 { \ 2173 Map* map; \ 2174 if (!AllocatePartialMap((instance_type), (size)).To(&map)) return false; \ 2175 set_##field_name##_map(map); \ 2176 } 2177 2178 ALLOCATE_PARTIAL_MAP(FIXED_ARRAY_TYPE, kVariableSizeSentinel, fixed_array); 2179 fixed_array_map()->set_elements_kind(FAST_HOLEY_ELEMENTS); 2180 ALLOCATE_PARTIAL_MAP(ODDBALL_TYPE, Oddball::kSize, undefined); 2181 ALLOCATE_PARTIAL_MAP(ODDBALL_TYPE, Oddball::kSize, null); 2182 ALLOCATE_PARTIAL_MAP(ODDBALL_TYPE, Oddball::kSize, the_hole); 2183 2184 #undef ALLOCATE_PARTIAL_MAP 2185 } 2186 2187 // Allocate the empty array. 2188 { 2189 AllocationResult allocation = AllocateEmptyFixedArray(); 2190 if (!allocation.To(&obj)) return false; 2191 } 2192 set_empty_fixed_array(FixedArray::cast(obj)); 2193 2194 { 2195 AllocationResult allocation = Allocate(null_map(), OLD_SPACE); 2196 if (!allocation.To(&obj)) return false; 2197 } 2198 set_null_value(Oddball::cast(obj)); 2199 Oddball::cast(obj)->set_kind(Oddball::kNull); 2200 2201 { 2202 AllocationResult allocation = Allocate(undefined_map(), OLD_SPACE); 2203 if (!allocation.To(&obj)) return false; 2204 } 2205 set_undefined_value(Oddball::cast(obj)); 2206 Oddball::cast(obj)->set_kind(Oddball::kUndefined); 2207 DCHECK(!InNewSpace(undefined_value())); 2208 { 2209 AllocationResult allocation = Allocate(the_hole_map(), OLD_SPACE); 2210 if (!allocation.To(&obj)) return false; 2211 } 2212 set_the_hole_value(Oddball::cast(obj)); 2213 Oddball::cast(obj)->set_kind(Oddball::kTheHole); 2214 2215 // Set preliminary exception sentinel value before actually initializing it. 2216 set_exception(null_value()); 2217 2218 // Allocate the empty descriptor array. 2219 { 2220 AllocationResult allocation = AllocateEmptyFixedArray(); 2221 if (!allocation.To(&obj)) return false; 2222 } 2223 set_empty_descriptor_array(DescriptorArray::cast(obj)); 2224 2225 // Fix the instance_descriptors for the existing maps. 2226 FinalizePartialMap(this, meta_map()); 2227 FinalizePartialMap(this, fixed_array_map()); 2228 FinalizePartialMap(this, undefined_map()); 2229 undefined_map()->set_is_undetectable(); 2230 FinalizePartialMap(this, null_map()); 2231 null_map()->set_is_undetectable(); 2232 FinalizePartialMap(this, the_hole_map()); 2233 2234 { // Map allocation 2235 #define ALLOCATE_MAP(instance_type, size, field_name) \ 2236 { \ 2237 Map* map; \ 2238 if (!AllocateMap((instance_type), size).To(&map)) return false; \ 2239 set_##field_name##_map(map); \ 2240 } 2241 2242 #define ALLOCATE_VARSIZE_MAP(instance_type, field_name) \ 2243 ALLOCATE_MAP(instance_type, kVariableSizeSentinel, field_name) 2244 2245 #define ALLOCATE_PRIMITIVE_MAP(instance_type, size, field_name, \ 2246 constructor_function_index) \ 2247 { \ 2248 ALLOCATE_MAP((instance_type), (size), field_name); \ 2249 field_name##_map()->SetConstructorFunctionIndex( \ 2250 (constructor_function_index)); \ 2251 } 2252 2253 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, fixed_cow_array) 2254 fixed_cow_array_map()->set_elements_kind(FAST_HOLEY_ELEMENTS); 2255 DCHECK_NE(fixed_array_map(), fixed_cow_array_map()); 2256 2257 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, scope_info) 2258 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, module_info) 2259 ALLOCATE_PRIMITIVE_MAP(HEAP_NUMBER_TYPE, HeapNumber::kSize, heap_number, 2260 Context::NUMBER_FUNCTION_INDEX) 2261 ALLOCATE_MAP(MUTABLE_HEAP_NUMBER_TYPE, HeapNumber::kSize, 2262 mutable_heap_number) 2263 ALLOCATE_PRIMITIVE_MAP(SYMBOL_TYPE, Symbol::kSize, symbol, 2264 Context::SYMBOL_FUNCTION_INDEX) 2265 #define ALLOCATE_SIMD128_MAP(TYPE, Type, type, lane_count, lane_type) \ 2266 ALLOCATE_PRIMITIVE_MAP(SIMD128_VALUE_TYPE, Type::kSize, type, \ 2267 Context::TYPE##_FUNCTION_INDEX) 2268 SIMD128_TYPES(ALLOCATE_SIMD128_MAP) 2269 #undef ALLOCATE_SIMD128_MAP 2270 ALLOCATE_MAP(FOREIGN_TYPE, Foreign::kSize, foreign) 2271 2272 ALLOCATE_PRIMITIVE_MAP(ODDBALL_TYPE, Oddball::kSize, boolean, 2273 Context::BOOLEAN_FUNCTION_INDEX); 2274 ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, uninitialized); 2275 ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, arguments_marker); 2276 ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, no_interceptor_result_sentinel); 2277 ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, exception); 2278 ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, termination_exception); 2279 ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, optimized_out); 2280 ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, stale_register); 2281 2282 for (unsigned i = 0; i < arraysize(string_type_table); i++) { 2283 const StringTypeTable& entry = string_type_table[i]; 2284 { 2285 AllocationResult allocation = AllocateMap(entry.type, entry.size); 2286 if (!allocation.To(&obj)) return false; 2287 } 2288 Map* map = Map::cast(obj); 2289 map->SetConstructorFunctionIndex(Context::STRING_FUNCTION_INDEX); 2290 // Mark cons string maps as unstable, because their objects can change 2291 // maps during GC. 2292 if (StringShape(entry.type).IsCons()) map->mark_unstable(); 2293 roots_[entry.index] = map; 2294 } 2295 2296 { // Create a separate external one byte string map for native sources. 2297 AllocationResult allocation = 2298 AllocateMap(SHORT_EXTERNAL_ONE_BYTE_STRING_TYPE, 2299 ExternalOneByteString::kShortSize); 2300 if (!allocation.To(&obj)) return false; 2301 Map* map = Map::cast(obj); 2302 map->SetConstructorFunctionIndex(Context::STRING_FUNCTION_INDEX); 2303 set_native_source_string_map(map); 2304 } 2305 2306 ALLOCATE_VARSIZE_MAP(FIXED_DOUBLE_ARRAY_TYPE, fixed_double_array) 2307 fixed_double_array_map()->set_elements_kind(FAST_HOLEY_DOUBLE_ELEMENTS); 2308 ALLOCATE_VARSIZE_MAP(BYTE_ARRAY_TYPE, byte_array) 2309 ALLOCATE_VARSIZE_MAP(BYTECODE_ARRAY_TYPE, bytecode_array) 2310 ALLOCATE_VARSIZE_MAP(FREE_SPACE_TYPE, free_space) 2311 2312 #define ALLOCATE_FIXED_TYPED_ARRAY_MAP(Type, type, TYPE, ctype, size) \ 2313 ALLOCATE_VARSIZE_MAP(FIXED_##TYPE##_ARRAY_TYPE, fixed_##type##_array) 2314 2315 TYPED_ARRAYS(ALLOCATE_FIXED_TYPED_ARRAY_MAP) 2316 #undef ALLOCATE_FIXED_TYPED_ARRAY_MAP 2317 2318 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, sloppy_arguments_elements) 2319 2320 ALLOCATE_VARSIZE_MAP(CODE_TYPE, code) 2321 2322 ALLOCATE_MAP(CELL_TYPE, Cell::kSize, cell) 2323 ALLOCATE_MAP(PROPERTY_CELL_TYPE, PropertyCell::kSize, global_property_cell) 2324 ALLOCATE_MAP(WEAK_CELL_TYPE, WeakCell::kSize, weak_cell) 2325 ALLOCATE_MAP(FILLER_TYPE, kPointerSize, one_pointer_filler) 2326 ALLOCATE_MAP(FILLER_TYPE, 2 * kPointerSize, two_pointer_filler) 2327 2328 ALLOCATE_VARSIZE_MAP(TRANSITION_ARRAY_TYPE, transition_array) 2329 2330 for (unsigned i = 0; i < arraysize(struct_table); i++) { 2331 const StructTable& entry = struct_table[i]; 2332 Map* map; 2333 if (!AllocateMap(entry.type, entry.size).To(&map)) return false; 2334 roots_[entry.index] = map; 2335 } 2336 2337 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, hash_table) 2338 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, ordered_hash_table) 2339 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, unseeded_number_dictionary) 2340 2341 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, function_context) 2342 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, catch_context) 2343 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, with_context) 2344 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, debug_evaluate_context) 2345 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, block_context) 2346 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, module_context) 2347 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, script_context) 2348 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, script_context_table) 2349 2350 ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, native_context) 2351 native_context_map()->set_dictionary_map(true); 2352 native_context_map()->set_visitor_id( 2353 StaticVisitorBase::kVisitNativeContext); 2354 2355 ALLOCATE_MAP(SHARED_FUNCTION_INFO_TYPE, SharedFunctionInfo::kAlignedSize, 2356 shared_function_info) 2357 2358 ALLOCATE_MAP(JS_MESSAGE_OBJECT_TYPE, JSMessageObject::kSize, message_object) 2359 ALLOCATE_MAP(JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize, external) 2360 external_map()->set_is_extensible(false); 2361 #undef ALLOCATE_PRIMITIVE_MAP 2362 #undef ALLOCATE_VARSIZE_MAP 2363 #undef ALLOCATE_MAP 2364 } 2365 2366 { 2367 AllocationResult allocation = AllocateEmptyScopeInfo(); 2368 if (!allocation.To(&obj)) return false; 2369 } 2370 2371 set_empty_scope_info(ScopeInfo::cast(obj)); 2372 { 2373 AllocationResult allocation = Allocate(boolean_map(), OLD_SPACE); 2374 if (!allocation.To(&obj)) return false; 2375 } 2376 set_true_value(Oddball::cast(obj)); 2377 Oddball::cast(obj)->set_kind(Oddball::kTrue); 2378 2379 { 2380 AllocationResult allocation = Allocate(boolean_map(), OLD_SPACE); 2381 if (!allocation.To(&obj)) return false; 2382 } 2383 set_false_value(Oddball::cast(obj)); 2384 Oddball::cast(obj)->set_kind(Oddball::kFalse); 2385 2386 { // Empty arrays 2387 { 2388 ByteArray* byte_array; 2389 if (!AllocateByteArray(0, TENURED).To(&byte_array)) return false; 2390 set_empty_byte_array(byte_array); 2391 } 2392 2393 #define ALLOCATE_EMPTY_FIXED_TYPED_ARRAY(Type, type, TYPE, ctype, size) \ 2394 { \ 2395 FixedTypedArrayBase* obj; \ 2396 if (!AllocateEmptyFixedTypedArray(kExternal##Type##Array).To(&obj)) \ 2397 return false; \ 2398 set_empty_fixed_##type##_array(obj); \ 2399 } 2400 2401 TYPED_ARRAYS(ALLOCATE_EMPTY_FIXED_TYPED_ARRAY) 2402 #undef ALLOCATE_EMPTY_FIXED_TYPED_ARRAY 2403 } 2404 DCHECK(!InNewSpace(empty_fixed_array())); 2405 return true; 2406 } 2407 2408 2409 AllocationResult Heap::AllocateHeapNumber(double value, MutableMode mode, 2410 PretenureFlag pretenure) { 2411 // Statically ensure that it is safe to allocate heap numbers in paged 2412 // spaces. 2413 int size = HeapNumber::kSize; 2414 STATIC_ASSERT(HeapNumber::kSize <= kMaxRegularHeapObjectSize); 2415 2416 AllocationSpace space = SelectSpace(pretenure); 2417 2418 HeapObject* result = nullptr; 2419 { 2420 AllocationResult allocation = AllocateRaw(size, space, kDoubleUnaligned); 2421 if (!allocation.To(&result)) return allocation; 2422 } 2423 2424 Map* map = mode == MUTABLE ? mutable_heap_number_map() : heap_number_map(); 2425 HeapObject::cast(result)->set_map_no_write_barrier(map); 2426 HeapNumber::cast(result)->set_value(value); 2427 return result; 2428 } 2429 2430 #define SIMD_ALLOCATE_DEFINITION(TYPE, Type, type, lane_count, lane_type) \ 2431 AllocationResult Heap::Allocate##Type(lane_type lanes[lane_count], \ 2432 PretenureFlag pretenure) { \ 2433 int size = Type::kSize; \ 2434 STATIC_ASSERT(Type::kSize <= kMaxRegularHeapObjectSize); \ 2435 \ 2436 AllocationSpace space = SelectSpace(pretenure); \ 2437 \ 2438 HeapObject* result = nullptr; \ 2439 { \ 2440 AllocationResult allocation = \ 2441 AllocateRaw(size, space, kSimd128Unaligned); \ 2442 if (!allocation.To(&result)) return allocation; \ 2443 } \ 2444 \ 2445 result->set_map_no_write_barrier(type##_map()); \ 2446 Type* instance = Type::cast(result); \ 2447 for (int i = 0; i < lane_count; i++) { \ 2448 instance->set_lane(i, lanes[i]); \ 2449 } \ 2450 return result; \ 2451 } 2452 SIMD128_TYPES(SIMD_ALLOCATE_DEFINITION) 2453 #undef SIMD_ALLOCATE_DEFINITION 2454 2455 2456 AllocationResult Heap::AllocateCell(Object* value) { 2457 int size = Cell::kSize; 2458 STATIC_ASSERT(Cell::kSize <= kMaxRegularHeapObjectSize); 2459 2460 HeapObject* result = nullptr; 2461 { 2462 AllocationResult allocation = AllocateRaw(size, OLD_SPACE); 2463 if (!allocation.To(&result)) return allocation; 2464 } 2465 result->set_map_no_write_barrier(cell_map()); 2466 Cell::cast(result)->set_value(value); 2467 return result; 2468 } 2469 2470 AllocationResult Heap::AllocatePropertyCell() { 2471 int size = PropertyCell::kSize; 2472 STATIC_ASSERT(PropertyCell::kSize <= kMaxRegularHeapObjectSize); 2473 2474 HeapObject* result = nullptr; 2475 AllocationResult allocation = AllocateRaw(size, OLD_SPACE); 2476 if (!allocation.To(&result)) return allocation; 2477 2478 result->set_map_no_write_barrier(global_property_cell_map()); 2479 PropertyCell* cell = PropertyCell::cast(result); 2480 cell->set_dependent_code(DependentCode::cast(empty_fixed_array()), 2481 SKIP_WRITE_BARRIER); 2482 cell->set_property_details(PropertyDetails(Smi::kZero)); 2483 cell->set_value(the_hole_value()); 2484 return result; 2485 } 2486 2487 2488 AllocationResult Heap::AllocateWeakCell(HeapObject* value) { 2489 int size = WeakCell::kSize; 2490 STATIC_ASSERT(WeakCell::kSize <= kMaxRegularHeapObjectSize); 2491 HeapObject* result = nullptr; 2492 { 2493 AllocationResult allocation = AllocateRaw(size, OLD_SPACE); 2494 if (!allocation.To(&result)) return allocation; 2495 } 2496 result->set_map_no_write_barrier(weak_cell_map()); 2497 WeakCell::cast(result)->initialize(value); 2498 WeakCell::cast(result)->clear_next(the_hole_value()); 2499 return result; 2500 } 2501 2502 2503 AllocationResult Heap::AllocateTransitionArray(int capacity) { 2504 DCHECK(capacity > 0); 2505 HeapObject* raw_array = nullptr; 2506 { 2507 AllocationResult allocation = AllocateRawFixedArray(capacity, TENURED); 2508 if (!allocation.To(&raw_array)) return allocation; 2509 } 2510 raw_array->set_map_no_write_barrier(transition_array_map()); 2511 TransitionArray* array = TransitionArray::cast(raw_array); 2512 array->set_length(capacity); 2513 MemsetPointer(array->data_start(), undefined_value(), capacity); 2514 // Transition arrays are tenured. When black allocation is on we have to 2515 // add the transition array to the list of encountered_transition_arrays. 2516 if (incremental_marking()->black_allocation()) { 2517 array->set_next_link(encountered_transition_arrays(), 2518 UPDATE_WEAK_WRITE_BARRIER); 2519 set_encountered_transition_arrays(array); 2520 } else { 2521 array->set_next_link(undefined_value(), SKIP_WRITE_BARRIER); 2522 } 2523 return array; 2524 } 2525 2526 2527 void Heap::CreateApiObjects() { 2528 HandleScope scope(isolate()); 2529 set_message_listeners(*TemplateList::New(isolate(), 2)); 2530 } 2531 2532 2533 void Heap::CreateJSEntryStub() { 2534 JSEntryStub stub(isolate(), StackFrame::ENTRY); 2535 set_js_entry_code(*stub.GetCode()); 2536 } 2537 2538 2539 void Heap::CreateJSConstructEntryStub() { 2540 JSEntryStub stub(isolate(), StackFrame::ENTRY_CONSTRUCT); 2541 set_js_construct_entry_code(*stub.GetCode()); 2542 } 2543 2544 2545 void Heap::CreateFixedStubs() { 2546 // Here we create roots for fixed stubs. They are needed at GC 2547 // for cooking and uncooking (check out frames.cc). 2548 // The eliminates the need for doing dictionary lookup in the 2549 // stub cache for these stubs. 2550 HandleScope scope(isolate()); 2551 2552 // Create stubs that should be there, so we don't unexpectedly have to 2553 // create them if we need them during the creation of another stub. 2554 // Stub creation mixes raw pointers and handles in an unsafe manner so 2555 // we cannot create stubs while we are creating stubs. 2556 CodeStub::GenerateStubsAheadOfTime(isolate()); 2557 2558 // MacroAssembler::Abort calls (usually enabled with --debug-code) depend on 2559 // CEntryStub, so we need to call GenerateStubsAheadOfTime before JSEntryStub 2560 // is created. 2561 2562 // gcc-4.4 has problem generating correct code of following snippet: 2563 // { JSEntryStub stub; 2564 // js_entry_code_ = *stub.GetCode(); 2565 // } 2566 // { JSConstructEntryStub stub; 2567 // js_construct_entry_code_ = *stub.GetCode(); 2568 // } 2569 // To workaround the problem, make separate functions without inlining. 2570 Heap::CreateJSEntryStub(); 2571 Heap::CreateJSConstructEntryStub(); 2572 } 2573 2574 2575 void Heap::CreateInitialObjects() { 2576 HandleScope scope(isolate()); 2577 Factory* factory = isolate()->factory(); 2578 2579 // The -0 value must be set before NewNumber works. 2580 set_minus_zero_value(*factory->NewHeapNumber(-0.0, IMMUTABLE, TENURED)); 2581 DCHECK(std::signbit(minus_zero_value()->Number()) != 0); 2582 2583 set_nan_value(*factory->NewHeapNumber( 2584 std::numeric_limits<double>::quiet_NaN(), IMMUTABLE, TENURED)); 2585 set_hole_nan_value(*factory->NewHeapNumber(bit_cast<double>(kHoleNanInt64), 2586 IMMUTABLE, TENURED)); 2587 set_infinity_value(*factory->NewHeapNumber(V8_INFINITY, IMMUTABLE, TENURED)); 2588 set_minus_infinity_value( 2589 *factory->NewHeapNumber(-V8_INFINITY, IMMUTABLE, TENURED)); 2590 2591 // Allocate initial string table. 2592 set_string_table(*StringTable::New(isolate(), kInitialStringTableSize)); 2593 2594 // Allocate 2595 2596 // Finish initializing oddballs after creating the string table. 2597 Oddball::Initialize(isolate(), factory->undefined_value(), "undefined", 2598 factory->nan_value(), "undefined", Oddball::kUndefined); 2599 2600 // Initialize the null_value. 2601 Oddball::Initialize(isolate(), factory->null_value(), "null", 2602 handle(Smi::kZero, isolate()), "object", Oddball::kNull); 2603 2604 // Initialize the_hole_value. 2605 Oddball::Initialize(isolate(), factory->the_hole_value(), "hole", 2606 factory->hole_nan_value(), "undefined", 2607 Oddball::kTheHole); 2608 2609 // Initialize the true_value. 2610 Oddball::Initialize(isolate(), factory->true_value(), "true", 2611 handle(Smi::FromInt(1), isolate()), "boolean", 2612 Oddball::kTrue); 2613 2614 // Initialize the false_value. 2615 Oddball::Initialize(isolate(), factory->false_value(), "false", 2616 handle(Smi::kZero, isolate()), "boolean", 2617 Oddball::kFalse); 2618 2619 set_uninitialized_value( 2620 *factory->NewOddball(factory->uninitialized_map(), "uninitialized", 2621 handle(Smi::FromInt(-1), isolate()), "undefined", 2622 Oddball::kUninitialized)); 2623 2624 set_arguments_marker( 2625 *factory->NewOddball(factory->arguments_marker_map(), "arguments_marker", 2626 handle(Smi::FromInt(-4), isolate()), "undefined", 2627 Oddball::kArgumentsMarker)); 2628 2629 set_no_interceptor_result_sentinel(*factory->NewOddball( 2630 factory->no_interceptor_result_sentinel_map(), 2631 "no_interceptor_result_sentinel", handle(Smi::FromInt(-2), isolate()), 2632 "undefined", Oddball::kOther)); 2633 2634 set_termination_exception(*factory->NewOddball( 2635 factory->termination_exception_map(), "termination_exception", 2636 handle(Smi::FromInt(-3), isolate()), "undefined", Oddball::kOther)); 2637 2638 set_exception(*factory->NewOddball(factory->exception_map(), "exception", 2639 handle(Smi::FromInt(-5), isolate()), 2640 "undefined", Oddball::kException)); 2641 2642 set_optimized_out(*factory->NewOddball(factory->optimized_out_map(), 2643 "optimized_out", 2644 handle(Smi::FromInt(-6), isolate()), 2645 "undefined", Oddball::kOptimizedOut)); 2646 2647 set_stale_register( 2648 *factory->NewOddball(factory->stale_register_map(), "stale_register", 2649 handle(Smi::FromInt(-7), isolate()), "undefined", 2650 Oddball::kStaleRegister)); 2651 2652 for (unsigned i = 0; i < arraysize(constant_string_table); i++) { 2653 Handle<String> str = 2654 factory->InternalizeUtf8String(constant_string_table[i].contents); 2655 roots_[constant_string_table[i].index] = *str; 2656 } 2657 2658 // Create the code_stubs dictionary. The initial size is set to avoid 2659 // expanding the dictionary during bootstrapping. 2660 set_code_stubs(*UnseededNumberDictionary::New(isolate(), 128)); 2661 2662 set_instanceof_cache_function(Smi::kZero); 2663 set_instanceof_cache_map(Smi::kZero); 2664 set_instanceof_cache_answer(Smi::kZero); 2665 2666 { 2667 HandleScope scope(isolate()); 2668 #define SYMBOL_INIT(name) \ 2669 { \ 2670 Handle<String> name##d = factory->NewStringFromStaticChars(#name); \ 2671 Handle<Symbol> symbol(isolate()->factory()->NewPrivateSymbol()); \ 2672 symbol->set_name(*name##d); \ 2673 roots_[k##name##RootIndex] = *symbol; \ 2674 } 2675 PRIVATE_SYMBOL_LIST(SYMBOL_INIT) 2676 #undef SYMBOL_INIT 2677 } 2678 2679 { 2680 HandleScope scope(isolate()); 2681 #define SYMBOL_INIT(name, description) \ 2682 Handle<Symbol> name = factory->NewSymbol(); \ 2683 Handle<String> name##d = factory->NewStringFromStaticChars(#description); \ 2684 name->set_name(*name##d); \ 2685 roots_[k##name##RootIndex] = *name; 2686 PUBLIC_SYMBOL_LIST(SYMBOL_INIT) 2687 #undef SYMBOL_INIT 2688 2689 #define SYMBOL_INIT(name, description) \ 2690 Handle<Symbol> name = factory->NewSymbol(); \ 2691 Handle<String> name##d = factory->NewStringFromStaticChars(#description); \ 2692 name->set_is_well_known_symbol(true); \ 2693 name->set_name(*name##d); \ 2694 roots_[k##name##RootIndex] = *name; 2695 WELL_KNOWN_SYMBOL_LIST(SYMBOL_INIT) 2696 #undef SYMBOL_INIT 2697 } 2698 2699 Handle<NameDictionary> empty_properties_dictionary = 2700 NameDictionary::New(isolate(), 0, TENURED); 2701 empty_properties_dictionary->SetRequiresCopyOnCapacityChange(); 2702 set_empty_properties_dictionary(*empty_properties_dictionary); 2703 2704 set_number_string_cache( 2705 *factory->NewFixedArray(kInitialNumberStringCacheSize * 2, TENURED)); 2706 2707 // Allocate cache for single character one byte strings. 2708 set_single_character_string_cache( 2709 *factory->NewFixedArray(String::kMaxOneByteCharCode + 1, TENURED)); 2710 2711 // Allocate cache for string split and regexp-multiple. 2712 set_string_split_cache(*factory->NewFixedArray( 2713 RegExpResultsCache::kRegExpResultsCacheSize, TENURED)); 2714 set_regexp_multiple_cache(*factory->NewFixedArray( 2715 RegExpResultsCache::kRegExpResultsCacheSize, TENURED)); 2716 2717 // Allocate cache for external strings pointing to native source code. 2718 set_natives_source_cache( 2719 *factory->NewFixedArray(Natives::GetBuiltinsCount())); 2720 2721 set_experimental_natives_source_cache( 2722 *factory->NewFixedArray(ExperimentalNatives::GetBuiltinsCount())); 2723 2724 set_extra_natives_source_cache( 2725 *factory->NewFixedArray(ExtraNatives::GetBuiltinsCount())); 2726 2727 set_experimental_extra_natives_source_cache( 2728 *factory->NewFixedArray(ExperimentalExtraNatives::GetBuiltinsCount())); 2729 2730 set_undefined_cell(*factory->NewCell(factory->undefined_value())); 2731 2732 // The symbol registry is initialized lazily. 2733 set_symbol_registry(Smi::kZero); 2734 2735 // Microtask queue uses the empty fixed array as a sentinel for "empty". 2736 // Number of queued microtasks stored in Isolate::pending_microtask_count(). 2737 set_microtask_queue(empty_fixed_array()); 2738 2739 { 2740 StaticFeedbackVectorSpec spec; 2741 FeedbackVectorSlot slot = spec.AddLoadICSlot(); 2742 DCHECK_EQ(slot, FeedbackVectorSlot(TypeFeedbackVector::kDummyLoadICSlot)); 2743 2744 slot = spec.AddKeyedLoadICSlot(); 2745 DCHECK_EQ(slot, 2746 FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedLoadICSlot)); 2747 2748 slot = spec.AddStoreICSlot(); 2749 DCHECK_EQ(slot, FeedbackVectorSlot(TypeFeedbackVector::kDummyStoreICSlot)); 2750 2751 slot = spec.AddKeyedStoreICSlot(); 2752 DCHECK_EQ(slot, 2753 FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot)); 2754 2755 Handle<TypeFeedbackMetadata> dummy_metadata = 2756 TypeFeedbackMetadata::New(isolate(), &spec); 2757 Handle<TypeFeedbackVector> dummy_vector = 2758 TypeFeedbackVector::New(isolate(), dummy_metadata); 2759 2760 set_dummy_vector(*dummy_vector); 2761 2762 // Now initialize dummy vector's entries. 2763 LoadICNexus(isolate()).ConfigureMegamorphic(); 2764 StoreICNexus(isolate()).ConfigureMegamorphic(); 2765 KeyedLoadICNexus(isolate()).ConfigureMegamorphicKeyed(PROPERTY); 2766 KeyedStoreICNexus(isolate()).ConfigureMegamorphicKeyed(PROPERTY); 2767 } 2768 2769 { 2770 // Create a canonical empty TypeFeedbackVector, which is shared by all 2771 // functions that don't need actual type feedback slots. Note however 2772 // that all these functions will share the same invocation count, but 2773 // that shouldn't matter since we only use the invocation count to 2774 // relativize the absolute call counts, but we can only have call counts 2775 // if we have actual feedback slots. 2776 Handle<FixedArray> empty_type_feedback_vector = factory->NewFixedArray( 2777 TypeFeedbackVector::kReservedIndexCount, TENURED); 2778 empty_type_feedback_vector->set(TypeFeedbackVector::kMetadataIndex, 2779 empty_fixed_array()); 2780 empty_type_feedback_vector->set(TypeFeedbackVector::kInvocationCountIndex, 2781 Smi::kZero); 2782 set_empty_type_feedback_vector(*empty_type_feedback_vector); 2783 2784 // We use a canonical empty LiteralsArray for all functions that neither 2785 // have literals nor need a TypeFeedbackVector (besides the invocation 2786 // count special slot). 2787 Handle<FixedArray> empty_literals_array = 2788 factory->NewFixedArray(1, TENURED); 2789 empty_literals_array->set(0, *empty_type_feedback_vector); 2790 set_empty_literals_array(*empty_literals_array); 2791 } 2792 2793 { 2794 Handle<FixedArray> empty_sloppy_arguments_elements = 2795 factory->NewFixedArray(2, TENURED); 2796 empty_sloppy_arguments_elements->set_map(sloppy_arguments_elements_map()); 2797 set_empty_sloppy_arguments_elements(*empty_sloppy_arguments_elements); 2798 } 2799 2800 { 2801 Handle<WeakCell> cell = factory->NewWeakCell(factory->undefined_value()); 2802 set_empty_weak_cell(*cell); 2803 cell->clear(); 2804 } 2805 2806 set_detached_contexts(empty_fixed_array()); 2807 set_retained_maps(ArrayList::cast(empty_fixed_array())); 2808 2809 set_weak_object_to_code_table( 2810 *WeakHashTable::New(isolate(), 16, USE_DEFAULT_MINIMUM_CAPACITY, 2811 TENURED)); 2812 2813 set_weak_new_space_object_to_code_list( 2814 ArrayList::cast(*(factory->NewFixedArray(16, TENURED)))); 2815 weak_new_space_object_to_code_list()->SetLength(0); 2816 2817 set_script_list(Smi::kZero); 2818 2819 Handle<SeededNumberDictionary> slow_element_dictionary = 2820 SeededNumberDictionary::New(isolate(), 0, TENURED); 2821 slow_element_dictionary->set_requires_slow_elements(); 2822 set_empty_slow_element_dictionary(*slow_element_dictionary); 2823 2824 set_materialized_objects(*factory->NewFixedArray(0, TENURED)); 2825 2826 // Handling of script id generation is in Heap::NextScriptId(). 2827 set_last_script_id(Smi::FromInt(v8::UnboundScript::kNoScriptId)); 2828 set_next_template_serial_number(Smi::kZero); 2829 2830 // Allocate the empty script. 2831 Handle<Script> script = factory->NewScript(factory->empty_string()); 2832 script->set_type(Script::TYPE_NATIVE); 2833 set_empty_script(*script); 2834 2835 Handle<PropertyCell> cell = factory->NewPropertyCell(); 2836 cell->set_value(Smi::FromInt(Isolate::kProtectorValid)); 2837 set_array_protector(*cell); 2838 2839 cell = factory->NewPropertyCell(); 2840 cell->set_value(the_hole_value()); 2841 set_empty_property_cell(*cell); 2842 2843 cell = factory->NewPropertyCell(); 2844 cell->set_value(Smi::FromInt(Isolate::kProtectorValid)); 2845 set_has_instance_protector(*cell); 2846 2847 Handle<Cell> is_concat_spreadable_cell = factory->NewCell( 2848 handle(Smi::FromInt(Isolate::kProtectorValid), isolate())); 2849 set_is_concat_spreadable_protector(*is_concat_spreadable_cell); 2850 2851 Handle<Cell> species_cell = factory->NewCell( 2852 handle(Smi::FromInt(Isolate::kProtectorValid), isolate())); 2853 set_species_protector(*species_cell); 2854 2855 cell = factory->NewPropertyCell(); 2856 cell->set_value(Smi::FromInt(Isolate::kProtectorValid)); 2857 set_string_length_protector(*cell); 2858 2859 Handle<Cell> fast_array_iteration_cell = factory->NewCell( 2860 handle(Smi::FromInt(Isolate::kProtectorValid), isolate())); 2861 set_fast_array_iteration_protector(*fast_array_iteration_cell); 2862 2863 Handle<Cell> array_iterator_cell = factory->NewCell( 2864 handle(Smi::FromInt(Isolate::kProtectorValid), isolate())); 2865 set_array_iterator_protector(*array_iterator_cell); 2866 2867 set_serialized_templates(empty_fixed_array()); 2868 2869 set_weak_stack_trace_list(Smi::kZero); 2870 2871 set_noscript_shared_function_infos(Smi::kZero); 2872 2873 // Initialize context slot cache. 2874 isolate_->context_slot_cache()->Clear(); 2875 2876 // Initialize descriptor cache. 2877 isolate_->descriptor_lookup_cache()->Clear(); 2878 2879 // Initialize compilation cache. 2880 isolate_->compilation_cache()->Clear(); 2881 } 2882 2883 bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) { 2884 switch (root_index) { 2885 case kNumberStringCacheRootIndex: 2886 case kInstanceofCacheFunctionRootIndex: 2887 case kInstanceofCacheMapRootIndex: 2888 case kInstanceofCacheAnswerRootIndex: 2889 case kCodeStubsRootIndex: 2890 case kEmptyScriptRootIndex: 2891 case kSymbolRegistryRootIndex: 2892 case kScriptListRootIndex: 2893 case kMaterializedObjectsRootIndex: 2894 case kMicrotaskQueueRootIndex: 2895 case kDetachedContextsRootIndex: 2896 case kWeakObjectToCodeTableRootIndex: 2897 case kWeakNewSpaceObjectToCodeListRootIndex: 2898 case kRetainedMapsRootIndex: 2899 case kNoScriptSharedFunctionInfosRootIndex: 2900 case kWeakStackTraceListRootIndex: 2901 case kSerializedTemplatesRootIndex: 2902 // Smi values 2903 #define SMI_ENTRY(type, name, Name) case k##Name##RootIndex: 2904 SMI_ROOT_LIST(SMI_ENTRY) 2905 #undef SMI_ENTRY 2906 // String table 2907 case kStringTableRootIndex: 2908 return true; 2909 2910 default: 2911 return false; 2912 } 2913 } 2914 2915 2916 bool Heap::RootCanBeTreatedAsConstant(RootListIndex root_index) { 2917 return !RootCanBeWrittenAfterInitialization(root_index) && 2918 !InNewSpace(root(root_index)); 2919 } 2920 2921 2922 int Heap::FullSizeNumberStringCacheLength() { 2923 // Compute the size of the number string cache based on the max newspace size. 2924 // The number string cache has a minimum size based on twice the initial cache 2925 // size to ensure that it is bigger after being made 'full size'. 2926 size_t number_string_cache_size = max_semi_space_size_ / 512; 2927 number_string_cache_size = 2928 Max(static_cast<size_t>(kInitialNumberStringCacheSize * 2), 2929 Min<size_t>(0x4000u, number_string_cache_size)); 2930 // There is a string and a number per entry so the length is twice the number 2931 // of entries. 2932 return static_cast<int>(number_string_cache_size * 2); 2933 } 2934 2935 2936 void Heap::FlushNumberStringCache() { 2937 // Flush the number to string cache. 2938 int len = number_string_cache()->length(); 2939 for (int i = 0; i < len; i++) { 2940 number_string_cache()->set_undefined(i); 2941 } 2942 } 2943 2944 2945 Map* Heap::MapForFixedTypedArray(ExternalArrayType array_type) { 2946 return Map::cast(roots_[RootIndexForFixedTypedArray(array_type)]); 2947 } 2948 2949 2950 Heap::RootListIndex Heap::RootIndexForFixedTypedArray( 2951 ExternalArrayType array_type) { 2952 switch (array_type) { 2953 #define ARRAY_TYPE_TO_ROOT_INDEX(Type, type, TYPE, ctype, size) \ 2954 case kExternal##Type##Array: \ 2955 return kFixed##Type##ArrayMapRootIndex; 2956 2957 TYPED_ARRAYS(ARRAY_TYPE_TO_ROOT_INDEX) 2958 #undef ARRAY_TYPE_TO_ROOT_INDEX 2959 2960 default: 2961 UNREACHABLE(); 2962 return kUndefinedValueRootIndex; 2963 } 2964 } 2965 2966 2967 Heap::RootListIndex Heap::RootIndexForEmptyFixedTypedArray( 2968 ElementsKind elementsKind) { 2969 switch (elementsKind) { 2970 #define ELEMENT_KIND_TO_ROOT_INDEX(Type, type, TYPE, ctype, size) \ 2971 case TYPE##_ELEMENTS: \ 2972 return kEmptyFixed##Type##ArrayRootIndex; 2973 2974 TYPED_ARRAYS(ELEMENT_KIND_TO_ROOT_INDEX) 2975 #undef ELEMENT_KIND_TO_ROOT_INDEX 2976 default: 2977 UNREACHABLE(); 2978 return kUndefinedValueRootIndex; 2979 } 2980 } 2981 2982 2983 FixedTypedArrayBase* Heap::EmptyFixedTypedArrayForMap(Map* map) { 2984 return FixedTypedArrayBase::cast( 2985 roots_[RootIndexForEmptyFixedTypedArray(map->elements_kind())]); 2986 } 2987 2988 2989 AllocationResult Heap::AllocateForeign(Address address, 2990 PretenureFlag pretenure) { 2991 // Statically ensure that it is safe to allocate foreigns in paged spaces. 2992 STATIC_ASSERT(Foreign::kSize <= kMaxRegularHeapObjectSize); 2993 AllocationSpace space = (pretenure == TENURED) ? OLD_SPACE : NEW_SPACE; 2994 Foreign* result = nullptr; 2995 AllocationResult allocation = Allocate(foreign_map(), space); 2996 if (!allocation.To(&result)) return allocation; 2997 result->set_foreign_address(address); 2998 return result; 2999 } 3000 3001 3002 AllocationResult Heap::AllocateByteArray(int length, PretenureFlag pretenure) { 3003 if (length < 0 || length > ByteArray::kMaxLength) { 3004 v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true); 3005 } 3006 int size = ByteArray::SizeFor(length); 3007 AllocationSpace space = SelectSpace(pretenure); 3008 HeapObject* result = nullptr; 3009 { 3010 AllocationResult allocation = AllocateRaw(size, space); 3011 if (!allocation.To(&result)) return allocation; 3012 } 3013 3014 result->set_map_no_write_barrier(byte_array_map()); 3015 ByteArray::cast(result)->set_length(length); 3016 return result; 3017 } 3018 3019 3020 AllocationResult Heap::AllocateBytecodeArray(int length, 3021 const byte* const raw_bytecodes, 3022 int frame_size, 3023 int parameter_count, 3024 FixedArray* constant_pool) { 3025 if (length < 0 || length > BytecodeArray::kMaxLength) { 3026 v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true); 3027 } 3028 // Bytecode array is pretenured, so constant pool array should be to. 3029 DCHECK(!InNewSpace(constant_pool)); 3030 3031 int size = BytecodeArray::SizeFor(length); 3032 HeapObject* result = nullptr; 3033 { 3034 AllocationResult allocation = AllocateRaw(size, OLD_SPACE); 3035 if (!allocation.To(&result)) return allocation; 3036 } 3037 3038 result->set_map_no_write_barrier(bytecode_array_map()); 3039 BytecodeArray* instance = BytecodeArray::cast(result); 3040 instance->set_length(length); 3041 instance->set_frame_size(frame_size); 3042 instance->set_parameter_count(parameter_count); 3043 instance->set_interrupt_budget(interpreter::Interpreter::InterruptBudget()); 3044 instance->set_osr_loop_nesting_level(0); 3045 instance->set_constant_pool(constant_pool); 3046 instance->set_handler_table(empty_fixed_array()); 3047 instance->set_source_position_table(empty_byte_array()); 3048 CopyBytes(instance->GetFirstBytecodeAddress(), raw_bytecodes, length); 3049 3050 return result; 3051 } 3052 3053 void Heap::CreateFillerObjectAt(Address addr, int size, ClearRecordedSlots mode, 3054 ClearBlackArea black_area_mode) { 3055 if (size == 0) return; 3056 HeapObject* filler = HeapObject::FromAddress(addr); 3057 if (size == kPointerSize) { 3058 filler->set_map_no_write_barrier( 3059 reinterpret_cast<Map*>(root(kOnePointerFillerMapRootIndex))); 3060 } else if (size == 2 * kPointerSize) { 3061 filler->set_map_no_write_barrier( 3062 reinterpret_cast<Map*>(root(kTwoPointerFillerMapRootIndex))); 3063 } else { 3064 DCHECK_GT(size, 2 * kPointerSize); 3065 filler->set_map_no_write_barrier( 3066 reinterpret_cast<Map*>(root(kFreeSpaceMapRootIndex))); 3067 FreeSpace::cast(filler)->nobarrier_set_size(size); 3068 } 3069 if (mode == ClearRecordedSlots::kYes) { 3070 ClearRecordedSlotRange(addr, addr + size); 3071 } 3072 3073 // If the location where the filler is created is within a black area we have 3074 // to clear the mark bits of the filler space. 3075 if (black_area_mode == ClearBlackArea::kYes && 3076 incremental_marking()->black_allocation() && 3077 Marking::IsBlackOrGrey(ObjectMarking::MarkBitFrom(addr))) { 3078 Page* page = Page::FromAddress(addr); 3079 page->markbits()->ClearRange(page->AddressToMarkbitIndex(addr), 3080 page->AddressToMarkbitIndex(addr + size)); 3081 } 3082 3083 // At this point, we may be deserializing the heap from a snapshot, and 3084 // none of the maps have been created yet and are NULL. 3085 DCHECK((filler->map() == NULL && !deserialization_complete_) || 3086 filler->map()->IsMap()); 3087 } 3088 3089 3090 bool Heap::CanMoveObjectStart(HeapObject* object) { 3091 if (!FLAG_move_object_start) return false; 3092 3093 // Sampling heap profiler may have a reference to the object. 3094 if (isolate()->heap_profiler()->is_sampling_allocations()) return false; 3095 3096 Address address = object->address(); 3097 3098 if (lo_space()->Contains(object)) return false; 3099 3100 // We can move the object start if the page was already swept. 3101 return Page::FromAddress(address)->SweepingDone(); 3102 } 3103 3104 3105 void Heap::AdjustLiveBytes(HeapObject* object, int by, InvocationMode mode) { 3106 // As long as the inspected object is black and we are currently not iterating 3107 // the heap using HeapIterator, we can update the live byte count. We cannot 3108 // update while using HeapIterator because the iterator is temporarily 3109 // marking the whole object graph, without updating live bytes. 3110 if (lo_space()->Contains(object)) { 3111 lo_space()->AdjustLiveBytes(by); 3112 } else if (!in_heap_iterator() && 3113 !mark_compact_collector()->sweeping_in_progress() && 3114 Marking::IsBlack(ObjectMarking::MarkBitFrom(object->address()))) { 3115 if (mode == SEQUENTIAL_TO_SWEEPER) { 3116 MemoryChunk::IncrementLiveBytesFromGC(object, by); 3117 } else { 3118 MemoryChunk::IncrementLiveBytesFromMutator(object, by); 3119 } 3120 } 3121 } 3122 3123 3124 FixedArrayBase* Heap::LeftTrimFixedArray(FixedArrayBase* object, 3125 int elements_to_trim) { 3126 CHECK_NOT_NULL(object); 3127 DCHECK(!object->IsFixedTypedArrayBase()); 3128 DCHECK(!object->IsByteArray()); 3129 const int element_size = object->IsFixedArray() ? kPointerSize : kDoubleSize; 3130 const int bytes_to_trim = elements_to_trim * element_size; 3131 Map* map = object->map(); 3132 3133 // For now this trick is only applied to objects in new and paged space. 3134 // In large object space the object's start must coincide with chunk 3135 // and thus the trick is just not applicable. 3136 DCHECK(!lo_space()->Contains(object)); 3137 DCHECK(object->map() != fixed_cow_array_map()); 3138 3139 STATIC_ASSERT(FixedArrayBase::kMapOffset == 0); 3140 STATIC_ASSERT(FixedArrayBase::kLengthOffset == kPointerSize); 3141 STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize); 3142 3143 const int len = object->length(); 3144 DCHECK(elements_to_trim <= len); 3145 3146 // Calculate location of new array start. 3147 Address old_start = object->address(); 3148 Address new_start = old_start + bytes_to_trim; 3149 3150 // Transfer the mark bits to their new location if the object is not within 3151 // a black area. 3152 if (!incremental_marking()->black_allocation() || 3153 !Marking::IsBlack(ObjectMarking::MarkBitFrom(new_start))) { 3154 IncrementalMarking::TransferMark(this, old_start, new_start); 3155 } 3156 3157 // Technically in new space this write might be omitted (except for 3158 // debug mode which iterates through the heap), but to play safer 3159 // we still do it. 3160 CreateFillerObjectAt(old_start, bytes_to_trim, ClearRecordedSlots::kYes); 3161 // Initialize header of the trimmed array. Since left trimming is only 3162 // performed on pages which are not concurrently swept creating a filler 3163 // object does not require synchronization. 3164 DCHECK(CanMoveObjectStart(object)); 3165 Object** former_start = HeapObject::RawField(object, 0); 3166 int new_start_index = elements_to_trim * (element_size / kPointerSize); 3167 former_start[new_start_index] = map; 3168 former_start[new_start_index + 1] = Smi::FromInt(len - elements_to_trim); 3169 3170 FixedArrayBase* new_object = 3171 FixedArrayBase::cast(HeapObject::FromAddress(new_start)); 3172 3173 // Maintain consistency of live bytes during incremental marking 3174 AdjustLiveBytes(new_object, -bytes_to_trim, Heap::CONCURRENT_TO_SWEEPER); 3175 3176 // Remove recorded slots for the new map and length offset. 3177 ClearRecordedSlot(new_object, HeapObject::RawField(new_object, 0)); 3178 ClearRecordedSlot(new_object, HeapObject::RawField( 3179 new_object, FixedArrayBase::kLengthOffset)); 3180 3181 // Notify the heap profiler of change in object layout. 3182 OnMoveEvent(new_object, object, new_object->Size()); 3183 return new_object; 3184 } 3185 3186 3187 // Force instantiation of templatized method. 3188 template void Heap::RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>( 3189 FixedArrayBase*, int); 3190 template void Heap::RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>( 3191 FixedArrayBase*, int); 3192 3193 3194 template<Heap::InvocationMode mode> 3195 void Heap::RightTrimFixedArray(FixedArrayBase* object, int elements_to_trim) { 3196 const int len = object->length(); 3197 DCHECK_LE(elements_to_trim, len); 3198 DCHECK_GE(elements_to_trim, 0); 3199 3200 int bytes_to_trim; 3201 if (object->IsFixedTypedArrayBase()) { 3202 InstanceType type = object->map()->instance_type(); 3203 bytes_to_trim = 3204 FixedTypedArrayBase::TypedArraySize(type, len) - 3205 FixedTypedArrayBase::TypedArraySize(type, len - elements_to_trim); 3206 } else if (object->IsByteArray()) { 3207 int new_size = ByteArray::SizeFor(len - elements_to_trim); 3208 bytes_to_trim = ByteArray::SizeFor(len) - new_size; 3209 DCHECK_GE(bytes_to_trim, 0); 3210 } else { 3211 const int element_size = 3212 object->IsFixedArray() ? kPointerSize : kDoubleSize; 3213 bytes_to_trim = elements_to_trim * element_size; 3214 } 3215 3216 3217 // For now this trick is only applied to objects in new and paged space. 3218 DCHECK(object->map() != fixed_cow_array_map()); 3219 3220 if (bytes_to_trim == 0) { 3221 // No need to create filler and update live bytes counters, just initialize 3222 // header of the trimmed array. 3223 object->synchronized_set_length(len - elements_to_trim); 3224 return; 3225 } 3226 3227 // Calculate location of new array end. 3228 Address old_end = object->address() + object->Size(); 3229 Address new_end = old_end - bytes_to_trim; 3230 3231 // Technically in new space this write might be omitted (except for 3232 // debug mode which iterates through the heap), but to play safer 3233 // we still do it. 3234 // We do not create a filler for objects in large object space. 3235 // TODO(hpayer): We should shrink the large object page if the size 3236 // of the object changed significantly. 3237 if (!lo_space()->Contains(object)) { 3238 CreateFillerObjectAt(new_end, bytes_to_trim, ClearRecordedSlots::kYes); 3239 } 3240 3241 // Initialize header of the trimmed array. We are storing the new length 3242 // using release store after creating a filler for the left-over space to 3243 // avoid races with the sweeper thread. 3244 object->synchronized_set_length(len - elements_to_trim); 3245 3246 // Maintain consistency of live bytes during incremental marking 3247 AdjustLiveBytes(object, -bytes_to_trim, mode); 3248 3249 // Notify the heap profiler of change in object layout. The array may not be 3250 // moved during GC, and size has to be adjusted nevertheless. 3251 HeapProfiler* profiler = isolate()->heap_profiler(); 3252 if (profiler->is_tracking_allocations()) { 3253 profiler->UpdateObjectSizeEvent(object->address(), object->Size()); 3254 } 3255 } 3256 3257 3258 AllocationResult Heap::AllocateFixedTypedArrayWithExternalPointer( 3259 int length, ExternalArrayType array_type, void* external_pointer, 3260 PretenureFlag pretenure) { 3261 int size = FixedTypedArrayBase::kHeaderSize; 3262 AllocationSpace space = SelectSpace(pretenure); 3263 HeapObject* result = nullptr; 3264 { 3265 AllocationResult allocation = AllocateRaw(size, space); 3266 if (!allocation.To(&result)) return allocation; 3267 } 3268 3269 result->set_map_no_write_barrier(MapForFixedTypedArray(array_type)); 3270 FixedTypedArrayBase* elements = FixedTypedArrayBase::cast(result); 3271 elements->set_base_pointer(Smi::kZero, SKIP_WRITE_BARRIER); 3272 elements->set_external_pointer(external_pointer, SKIP_WRITE_BARRIER); 3273 elements->set_length(length); 3274 return elements; 3275 } 3276 3277 static void ForFixedTypedArray(ExternalArrayType array_type, int* element_size, 3278 ElementsKind* element_kind) { 3279 switch (array_type) { 3280 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 3281 case kExternal##Type##Array: \ 3282 *element_size = size; \ 3283 *element_kind = TYPE##_ELEMENTS; \ 3284 return; 3285 3286 TYPED_ARRAYS(TYPED_ARRAY_CASE) 3287 #undef TYPED_ARRAY_CASE 3288 3289 default: 3290 *element_size = 0; // Bogus 3291 *element_kind = UINT8_ELEMENTS; // Bogus 3292 UNREACHABLE(); 3293 } 3294 } 3295 3296 3297 AllocationResult Heap::AllocateFixedTypedArray(int length, 3298 ExternalArrayType array_type, 3299 bool initialize, 3300 PretenureFlag pretenure) { 3301 int element_size; 3302 ElementsKind elements_kind; 3303 ForFixedTypedArray(array_type, &element_size, &elements_kind); 3304 int size = OBJECT_POINTER_ALIGN(length * element_size + 3305 FixedTypedArrayBase::kDataOffset); 3306 AllocationSpace space = SelectSpace(pretenure); 3307 3308 HeapObject* object = nullptr; 3309 AllocationResult allocation = AllocateRaw( 3310 size, space, 3311 array_type == kExternalFloat64Array ? kDoubleAligned : kWordAligned); 3312 if (!allocation.To(&object)) return allocation; 3313 3314 object->set_map_no_write_barrier(MapForFixedTypedArray(array_type)); 3315 FixedTypedArrayBase* elements = FixedTypedArrayBase::cast(object); 3316 elements->set_base_pointer(elements, SKIP_WRITE_BARRIER); 3317 elements->set_external_pointer( 3318 ExternalReference::fixed_typed_array_base_data_offset().address(), 3319 SKIP_WRITE_BARRIER); 3320 elements->set_length(length); 3321 if (initialize) memset(elements->DataPtr(), 0, elements->DataSize()); 3322 return elements; 3323 } 3324 3325 3326 AllocationResult Heap::AllocateCode(int object_size, bool immovable) { 3327 DCHECK(IsAligned(static_cast<intptr_t>(object_size), kCodeAlignment)); 3328 AllocationResult allocation = AllocateRaw(object_size, CODE_SPACE); 3329 3330 HeapObject* result = nullptr; 3331 if (!allocation.To(&result)) return allocation; 3332 if (immovable) { 3333 Address address = result->address(); 3334 // Code objects which should stay at a fixed address are allocated either 3335 // in the first page of code space (objects on the first page of each space 3336 // are never moved) or in large object space. 3337 if (!code_space_->FirstPage()->Contains(address) && 3338 MemoryChunk::FromAddress(address)->owner()->identity() != LO_SPACE) { 3339 // Discard the first code allocation, which was on a page where it could 3340 // be moved. 3341 CreateFillerObjectAt(result->address(), object_size, 3342 ClearRecordedSlots::kNo); 3343 allocation = lo_space_->AllocateRaw(object_size, EXECUTABLE); 3344 if (!allocation.To(&result)) return allocation; 3345 OnAllocationEvent(result, object_size); 3346 } 3347 } 3348 3349 result->set_map_no_write_barrier(code_map()); 3350 Code* code = Code::cast(result); 3351 DCHECK(IsAligned(bit_cast<intptr_t>(code->address()), kCodeAlignment)); 3352 DCHECK(!memory_allocator()->code_range()->valid() || 3353 memory_allocator()->code_range()->contains(code->address()) || 3354 object_size <= code_space()->AreaSize()); 3355 code->set_gc_metadata(Smi::kZero); 3356 code->set_ic_age(global_ic_age_); 3357 return code; 3358 } 3359 3360 3361 AllocationResult Heap::CopyCode(Code* code) { 3362 AllocationResult allocation; 3363 3364 HeapObject* result = nullptr; 3365 // Allocate an object the same size as the code object. 3366 int obj_size = code->Size(); 3367 allocation = AllocateRaw(obj_size, CODE_SPACE); 3368 if (!allocation.To(&result)) return allocation; 3369 3370 // Copy code object. 3371 Address old_addr = code->address(); 3372 Address new_addr = result->address(); 3373 CopyBlock(new_addr, old_addr, obj_size); 3374 Code* new_code = Code::cast(result); 3375 3376 // Relocate the copy. 3377 DCHECK(IsAligned(bit_cast<intptr_t>(new_code->address()), kCodeAlignment)); 3378 DCHECK(!memory_allocator()->code_range()->valid() || 3379 memory_allocator()->code_range()->contains(code->address()) || 3380 obj_size <= code_space()->AreaSize()); 3381 new_code->Relocate(new_addr - old_addr); 3382 // We have to iterate over the object and process its pointers when black 3383 // allocation is on. 3384 incremental_marking()->IterateBlackObject(new_code); 3385 // Record all references to embedded objects in the new code object. 3386 RecordWritesIntoCode(new_code); 3387 return new_code; 3388 } 3389 3390 AllocationResult Heap::CopyBytecodeArray(BytecodeArray* bytecode_array) { 3391 int size = BytecodeArray::SizeFor(bytecode_array->length()); 3392 HeapObject* result = nullptr; 3393 { 3394 AllocationResult allocation = AllocateRaw(size, OLD_SPACE); 3395 if (!allocation.To(&result)) return allocation; 3396 } 3397 3398 result->set_map_no_write_barrier(bytecode_array_map()); 3399 BytecodeArray* copy = BytecodeArray::cast(result); 3400 copy->set_length(bytecode_array->length()); 3401 copy->set_frame_size(bytecode_array->frame_size()); 3402 copy->set_parameter_count(bytecode_array->parameter_count()); 3403 copy->set_constant_pool(bytecode_array->constant_pool()); 3404 copy->set_handler_table(bytecode_array->handler_table()); 3405 copy->set_source_position_table(bytecode_array->source_position_table()); 3406 copy->set_interrupt_budget(bytecode_array->interrupt_budget()); 3407 copy->set_osr_loop_nesting_level(bytecode_array->osr_loop_nesting_level()); 3408 bytecode_array->CopyBytecodesTo(copy); 3409 return copy; 3410 } 3411 3412 void Heap::InitializeAllocationMemento(AllocationMemento* memento, 3413 AllocationSite* allocation_site) { 3414 memento->set_map_no_write_barrier(allocation_memento_map()); 3415 DCHECK(allocation_site->map() == allocation_site_map()); 3416 memento->set_allocation_site(allocation_site, SKIP_WRITE_BARRIER); 3417 if (FLAG_allocation_site_pretenuring) { 3418 allocation_site->IncrementMementoCreateCount(); 3419 } 3420 } 3421 3422 3423 AllocationResult Heap::Allocate(Map* map, AllocationSpace space, 3424 AllocationSite* allocation_site) { 3425 DCHECK(gc_state_ == NOT_IN_GC); 3426 DCHECK(map->instance_type() != MAP_TYPE); 3427 int size = map->instance_size(); 3428 if (allocation_site != NULL) { 3429 size += AllocationMemento::kSize; 3430 } 3431 HeapObject* result = nullptr; 3432 AllocationResult allocation = AllocateRaw(size, space); 3433 if (!allocation.To(&result)) return allocation; 3434 // No need for write barrier since object is white and map is in old space. 3435 result->set_map_no_write_barrier(map); 3436 if (allocation_site != NULL) { 3437 AllocationMemento* alloc_memento = reinterpret_cast<AllocationMemento*>( 3438 reinterpret_cast<Address>(result) + map->instance_size()); 3439 InitializeAllocationMemento(alloc_memento, allocation_site); 3440 } 3441 return result; 3442 } 3443 3444 3445 void Heap::InitializeJSObjectFromMap(JSObject* obj, FixedArray* properties, 3446 Map* map) { 3447 obj->set_properties(properties); 3448 obj->initialize_elements(); 3449 // TODO(1240798): Initialize the object's body using valid initial values 3450 // according to the object's initial map. For example, if the map's 3451 // instance type is JS_ARRAY_TYPE, the length field should be initialized 3452 // to a number (e.g. Smi::kZero) and the elements initialized to a 3453 // fixed array (e.g. Heap::empty_fixed_array()). Currently, the object 3454 // verification code has to cope with (temporarily) invalid objects. See 3455 // for example, JSArray::JSArrayVerify). 3456 InitializeJSObjectBody(obj, map, JSObject::kHeaderSize); 3457 } 3458 3459 3460 void Heap::InitializeJSObjectBody(JSObject* obj, Map* map, int start_offset) { 3461 if (start_offset == map->instance_size()) return; 3462 DCHECK_LT(start_offset, map->instance_size()); 3463 3464 // We cannot always fill with one_pointer_filler_map because objects 3465 // created from API functions expect their internal fields to be initialized 3466 // with undefined_value. 3467 // Pre-allocated fields need to be initialized with undefined_value as well 3468 // so that object accesses before the constructor completes (e.g. in the 3469 // debugger) will not cause a crash. 3470 3471 // In case of Array subclassing the |map| could already be transitioned 3472 // to different elements kind from the initial map on which we track slack. 3473 bool in_progress = map->IsInobjectSlackTrackingInProgress(); 3474 Object* filler; 3475 if (in_progress) { 3476 filler = one_pointer_filler_map(); 3477 } else { 3478 filler = undefined_value(); 3479 } 3480 obj->InitializeBody(map, start_offset, Heap::undefined_value(), filler); 3481 if (in_progress) { 3482 map->FindRootMap()->InobjectSlackTrackingStep(); 3483 } 3484 } 3485 3486 3487 AllocationResult Heap::AllocateJSObjectFromMap( 3488 Map* map, PretenureFlag pretenure, AllocationSite* allocation_site) { 3489 // JSFunctions should be allocated using AllocateFunction to be 3490 // properly initialized. 3491 DCHECK(map->instance_type() != JS_FUNCTION_TYPE); 3492 3493 // Both types of global objects should be allocated using 3494 // AllocateGlobalObject to be properly initialized. 3495 DCHECK(map->instance_type() != JS_GLOBAL_OBJECT_TYPE); 3496 3497 // Allocate the backing storage for the properties. 3498 FixedArray* properties = empty_fixed_array(); 3499 3500 // Allocate the JSObject. 3501 AllocationSpace space = SelectSpace(pretenure); 3502 JSObject* js_obj = nullptr; 3503 AllocationResult allocation = Allocate(map, space, allocation_site); 3504 if (!allocation.To(&js_obj)) return allocation; 3505 3506 // Initialize the JSObject. 3507 InitializeJSObjectFromMap(js_obj, properties, map); 3508 DCHECK(js_obj->HasFastElements() || js_obj->HasFixedTypedArrayElements() || 3509 js_obj->HasFastStringWrapperElements() || 3510 js_obj->HasFastArgumentsElements()); 3511 return js_obj; 3512 } 3513 3514 3515 AllocationResult Heap::AllocateJSObject(JSFunction* constructor, 3516 PretenureFlag pretenure, 3517 AllocationSite* allocation_site) { 3518 DCHECK(constructor->has_initial_map()); 3519 3520 // Allocate the object based on the constructors initial map. 3521 AllocationResult allocation = AllocateJSObjectFromMap( 3522 constructor->initial_map(), pretenure, allocation_site); 3523 #ifdef DEBUG 3524 // Make sure result is NOT a global object if valid. 3525 HeapObject* obj = nullptr; 3526 DCHECK(!allocation.To(&obj) || !obj->IsJSGlobalObject()); 3527 #endif 3528 return allocation; 3529 } 3530 3531 3532 AllocationResult Heap::CopyJSObject(JSObject* source, AllocationSite* site) { 3533 // Make the clone. 3534 Map* map = source->map(); 3535 3536 // We can only clone regexps, normal objects, api objects, errors or arrays. 3537 // Copying anything else will break invariants. 3538 CHECK(map->instance_type() == JS_REGEXP_TYPE || 3539 map->instance_type() == JS_OBJECT_TYPE || 3540 map->instance_type() == JS_ERROR_TYPE || 3541 map->instance_type() == JS_ARRAY_TYPE || 3542 map->instance_type() == JS_API_OBJECT_TYPE || 3543 map->instance_type() == JS_SPECIAL_API_OBJECT_TYPE); 3544 3545 int object_size = map->instance_size(); 3546 HeapObject* clone = nullptr; 3547 3548 DCHECK(site == NULL || AllocationSite::CanTrack(map->instance_type())); 3549 3550 int adjusted_object_size = 3551 site != NULL ? object_size + AllocationMemento::kSize : object_size; 3552 AllocationResult allocation = AllocateRaw(adjusted_object_size, NEW_SPACE); 3553 if (!allocation.To(&clone)) return allocation; 3554 3555 SLOW_DCHECK(InNewSpace(clone)); 3556 // Since we know the clone is allocated in new space, we can copy 3557 // the contents without worrying about updating the write barrier. 3558 CopyBlock(clone->address(), source->address(), object_size); 3559 3560 if (site != NULL) { 3561 AllocationMemento* alloc_memento = reinterpret_cast<AllocationMemento*>( 3562 reinterpret_cast<Address>(clone) + object_size); 3563 InitializeAllocationMemento(alloc_memento, site); 3564 } 3565 3566 SLOW_DCHECK(JSObject::cast(clone)->GetElementsKind() == 3567 source->GetElementsKind()); 3568 FixedArrayBase* elements = FixedArrayBase::cast(source->elements()); 3569 FixedArray* properties = FixedArray::cast(source->properties()); 3570 // Update elements if necessary. 3571 if (elements->length() > 0) { 3572 FixedArrayBase* elem = nullptr; 3573 { 3574 AllocationResult allocation; 3575 if (elements->map() == fixed_cow_array_map()) { 3576 allocation = FixedArray::cast(elements); 3577 } else if (source->HasFastDoubleElements()) { 3578 allocation = CopyFixedDoubleArray(FixedDoubleArray::cast(elements)); 3579 } else { 3580 allocation = CopyFixedArray(FixedArray::cast(elements)); 3581 } 3582 if (!allocation.To(&elem)) return allocation; 3583 } 3584 JSObject::cast(clone)->set_elements(elem, SKIP_WRITE_BARRIER); 3585 } 3586 // Update properties if necessary. 3587 if (properties->length() > 0) { 3588 FixedArray* prop = nullptr; 3589 { 3590 AllocationResult allocation = CopyFixedArray(properties); 3591 if (!allocation.To(&prop)) return allocation; 3592 } 3593 JSObject::cast(clone)->set_properties(prop, SKIP_WRITE_BARRIER); 3594 } 3595 // Return the new clone. 3596 return clone; 3597 } 3598 3599 3600 static inline void WriteOneByteData(Vector<const char> vector, uint8_t* chars, 3601 int len) { 3602 // Only works for one byte strings. 3603 DCHECK(vector.length() == len); 3604 MemCopy(chars, vector.start(), len); 3605 } 3606 3607 static inline void WriteTwoByteData(Vector<const char> vector, uint16_t* chars, 3608 int len) { 3609 const uint8_t* stream = reinterpret_cast<const uint8_t*>(vector.start()); 3610 size_t stream_length = vector.length(); 3611 while (stream_length != 0) { 3612 size_t consumed = 0; 3613 uint32_t c = unibrow::Utf8::ValueOf(stream, stream_length, &consumed); 3614 DCHECK(c != unibrow::Utf8::kBadChar); 3615 DCHECK(consumed <= stream_length); 3616 stream_length -= consumed; 3617 stream += consumed; 3618 if (c > unibrow::Utf16::kMaxNonSurrogateCharCode) { 3619 len -= 2; 3620 if (len < 0) break; 3621 *chars++ = unibrow::Utf16::LeadSurrogate(c); 3622 *chars++ = unibrow::Utf16::TrailSurrogate(c); 3623 } else { 3624 len -= 1; 3625 if (len < 0) break; 3626 *chars++ = c; 3627 } 3628 } 3629 DCHECK(stream_length == 0); 3630 DCHECK(len == 0); 3631 } 3632 3633 3634 static inline void WriteOneByteData(String* s, uint8_t* chars, int len) { 3635 DCHECK(s->length() == len); 3636 String::WriteToFlat(s, chars, 0, len); 3637 } 3638 3639 3640 static inline void WriteTwoByteData(String* s, uint16_t* chars, int len) { 3641 DCHECK(s->length() == len); 3642 String::WriteToFlat(s, chars, 0, len); 3643 } 3644 3645 3646 template <bool is_one_byte, typename T> 3647 AllocationResult Heap::AllocateInternalizedStringImpl(T t, int chars, 3648 uint32_t hash_field) { 3649 DCHECK(chars >= 0); 3650 // Compute map and object size. 3651 int size; 3652 Map* map; 3653 3654 DCHECK_LE(0, chars); 3655 DCHECK_GE(String::kMaxLength, chars); 3656 if (is_one_byte) { 3657 map = one_byte_internalized_string_map(); 3658 size = SeqOneByteString::SizeFor(chars); 3659 } else { 3660 map = internalized_string_map(); 3661 size = SeqTwoByteString::SizeFor(chars); 3662 } 3663 3664 // Allocate string. 3665 HeapObject* result = nullptr; 3666 { 3667 AllocationResult allocation = AllocateRaw(size, OLD_SPACE); 3668 if (!allocation.To(&result)) return allocation; 3669 } 3670 3671 result->set_map_no_write_barrier(map); 3672 // Set length and hash fields of the allocated string. 3673 String* answer = String::cast(result); 3674 answer->set_length(chars); 3675 answer->set_hash_field(hash_field); 3676 3677 DCHECK_EQ(size, answer->Size()); 3678 3679 if (is_one_byte) { 3680 WriteOneByteData(t, SeqOneByteString::cast(answer)->GetChars(), chars); 3681 } else { 3682 WriteTwoByteData(t, SeqTwoByteString::cast(answer)->GetChars(), chars); 3683 } 3684 return answer; 3685 } 3686 3687 3688 // Need explicit instantiations. 3689 template AllocationResult Heap::AllocateInternalizedStringImpl<true>(String*, 3690 int, 3691 uint32_t); 3692 template AllocationResult Heap::AllocateInternalizedStringImpl<false>(String*, 3693 int, 3694 uint32_t); 3695 template AllocationResult Heap::AllocateInternalizedStringImpl<false>( 3696 Vector<const char>, int, uint32_t); 3697 3698 3699 AllocationResult Heap::AllocateRawOneByteString(int length, 3700 PretenureFlag pretenure) { 3701 DCHECK_LE(0, length); 3702 DCHECK_GE(String::kMaxLength, length); 3703 int size = SeqOneByteString::SizeFor(length); 3704 DCHECK(size <= SeqOneByteString::kMaxSize); 3705 AllocationSpace space = SelectSpace(pretenure); 3706 3707 HeapObject* result = nullptr; 3708 { 3709 AllocationResult allocation = AllocateRaw(size, space); 3710 if (!allocation.To(&result)) return allocation; 3711 } 3712 3713 // Partially initialize the object. 3714 result->set_map_no_write_barrier(one_byte_string_map()); 3715 String::cast(result)->set_length(length); 3716 String::cast(result)->set_hash_field(String::kEmptyHashField); 3717 DCHECK_EQ(size, HeapObject::cast(result)->Size()); 3718 3719 return result; 3720 } 3721 3722 3723 AllocationResult Heap::AllocateRawTwoByteString(int length, 3724 PretenureFlag pretenure) { 3725 DCHECK_LE(0, length); 3726 DCHECK_GE(String::kMaxLength, length); 3727 int size = SeqTwoByteString::SizeFor(length); 3728 DCHECK(size <= SeqTwoByteString::kMaxSize); 3729 AllocationSpace space = SelectSpace(pretenure); 3730 3731 HeapObject* result = nullptr; 3732 { 3733 AllocationResult allocation = AllocateRaw(size, space); 3734 if (!allocation.To(&result)) return allocation; 3735 } 3736 3737 // Partially initialize the object. 3738 result->set_map_no_write_barrier(string_map()); 3739 String::cast(result)->set_length(length); 3740 String::cast(result)->set_hash_field(String::kEmptyHashField); 3741 DCHECK_EQ(size, HeapObject::cast(result)->Size()); 3742 return result; 3743 } 3744 3745 3746 AllocationResult Heap::AllocateEmptyFixedArray() { 3747 int size = FixedArray::SizeFor(0); 3748 HeapObject* result = nullptr; 3749 { 3750 AllocationResult allocation = AllocateRaw(size, OLD_SPACE); 3751 if (!allocation.To(&result)) return allocation; 3752 } 3753 // Initialize the object. 3754 result->set_map_no_write_barrier(fixed_array_map()); 3755 FixedArray::cast(result)->set_length(0); 3756 return result; 3757 } 3758 3759 AllocationResult Heap::AllocateEmptyScopeInfo() { 3760 int size = FixedArray::SizeFor(0); 3761 HeapObject* result = nullptr; 3762 { 3763 AllocationResult allocation = AllocateRaw(size, OLD_SPACE); 3764 if (!allocation.To(&result)) return allocation; 3765 } 3766 // Initialize the object. 3767 result->set_map_no_write_barrier(scope_info_map()); 3768 FixedArray::cast(result)->set_length(0); 3769 return result; 3770 } 3771 3772 AllocationResult Heap::CopyAndTenureFixedCOWArray(FixedArray* src) { 3773 if (!InNewSpace(src)) { 3774 return src; 3775 } 3776 3777 int len = src->length(); 3778 HeapObject* obj = nullptr; 3779 { 3780 AllocationResult allocation = AllocateRawFixedArray(len, TENURED); 3781 if (!allocation.To(&obj)) return allocation; 3782 } 3783 obj->set_map_no_write_barrier(fixed_array_map()); 3784 FixedArray* result = FixedArray::cast(obj); 3785 result->set_length(len); 3786 3787 // Copy the content. 3788 DisallowHeapAllocation no_gc; 3789 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); 3790 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode); 3791 3792 // TODO(mvstanton): The map is set twice because of protection against calling 3793 // set() on a COW FixedArray. Issue v8:3221 created to track this, and 3794 // we might then be able to remove this whole method. 3795 HeapObject::cast(obj)->set_map_no_write_barrier(fixed_cow_array_map()); 3796 return result; 3797 } 3798 3799 3800 AllocationResult Heap::AllocateEmptyFixedTypedArray( 3801 ExternalArrayType array_type) { 3802 return AllocateFixedTypedArray(0, array_type, false, TENURED); 3803 } 3804 3805 3806 AllocationResult Heap::CopyFixedArrayAndGrow(FixedArray* src, int grow_by, 3807 PretenureFlag pretenure) { 3808 int old_len = src->length(); 3809 int new_len = old_len + grow_by; 3810 DCHECK(new_len >= old_len); 3811 HeapObject* obj = nullptr; 3812 { 3813 AllocationResult allocation = AllocateRawFixedArray(new_len, pretenure); 3814 if (!allocation.To(&obj)) return allocation; 3815 } 3816 3817 obj->set_map_no_write_barrier(fixed_array_map()); 3818 FixedArray* result = FixedArray::cast(obj); 3819 result->set_length(new_len); 3820 3821 // Copy the content. 3822 DisallowHeapAllocation no_gc; 3823 WriteBarrierMode mode = obj->GetWriteBarrierMode(no_gc); 3824 for (int i = 0; i < old_len; i++) result->set(i, src->get(i), mode); 3825 MemsetPointer(result->data_start() + old_len, undefined_value(), grow_by); 3826 return result; 3827 } 3828 3829 AllocationResult Heap::CopyFixedArrayUpTo(FixedArray* src, int new_len, 3830 PretenureFlag pretenure) { 3831 if (new_len == 0) return empty_fixed_array(); 3832 3833 DCHECK_LE(new_len, src->length()); 3834 3835 HeapObject* obj = nullptr; 3836 { 3837 AllocationResult allocation = AllocateRawFixedArray(new_len, pretenure); 3838 if (!allocation.To(&obj)) return allocation; 3839 } 3840 obj->set_map_no_write_barrier(fixed_array_map()); 3841 3842 FixedArray* result = FixedArray::cast(obj); 3843 result->set_length(new_len); 3844 3845 // Copy the content. 3846 DisallowHeapAllocation no_gc; 3847 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); 3848 for (int i = 0; i < new_len; i++) result->set(i, src->get(i), mode); 3849 return result; 3850 } 3851 3852 AllocationResult Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) { 3853 int len = src->length(); 3854 HeapObject* obj = nullptr; 3855 { 3856 AllocationResult allocation = AllocateRawFixedArray(len, NOT_TENURED); 3857 if (!allocation.To(&obj)) return allocation; 3858 } 3859 obj->set_map_no_write_barrier(map); 3860 3861 FixedArray* result = FixedArray::cast(obj); 3862 DisallowHeapAllocation no_gc; 3863 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); 3864 3865 // Eliminate the write barrier if possible. 3866 if (mode == SKIP_WRITE_BARRIER) { 3867 CopyBlock(obj->address() + kPointerSize, src->address() + kPointerSize, 3868 FixedArray::SizeFor(len) - kPointerSize); 3869 return obj; 3870 } 3871 3872 // Slow case: Just copy the content one-by-one. 3873 result->set_length(len); 3874 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode); 3875 return result; 3876 } 3877 3878 3879 AllocationResult Heap::CopyFixedDoubleArrayWithMap(FixedDoubleArray* src, 3880 Map* map) { 3881 int len = src->length(); 3882 HeapObject* obj = nullptr; 3883 { 3884 AllocationResult allocation = AllocateRawFixedDoubleArray(len, NOT_TENURED); 3885 if (!allocation.To(&obj)) return allocation; 3886 } 3887 obj->set_map_no_write_barrier(map); 3888 CopyBlock(obj->address() + FixedDoubleArray::kLengthOffset, 3889 src->address() + FixedDoubleArray::kLengthOffset, 3890 FixedDoubleArray::SizeFor(len) - FixedDoubleArray::kLengthOffset); 3891 return obj; 3892 } 3893 3894 3895 AllocationResult Heap::AllocateRawFixedArray(int length, 3896 PretenureFlag pretenure) { 3897 if (length < 0 || length > FixedArray::kMaxLength) { 3898 v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true); 3899 } 3900 int size = FixedArray::SizeFor(length); 3901 AllocationSpace space = SelectSpace(pretenure); 3902 3903 AllocationResult result = AllocateRaw(size, space); 3904 if (!result.IsRetry() && size > kMaxRegularHeapObjectSize && 3905 FLAG_use_marking_progress_bar) { 3906 MemoryChunk* chunk = 3907 MemoryChunk::FromAddress(result.ToObjectChecked()->address()); 3908 chunk->SetFlag(MemoryChunk::HAS_PROGRESS_BAR); 3909 } 3910 return result; 3911 } 3912 3913 3914 AllocationResult Heap::AllocateFixedArrayWithFiller(int length, 3915 PretenureFlag pretenure, 3916 Object* filler) { 3917 DCHECK(length >= 0); 3918 DCHECK(empty_fixed_array()->IsFixedArray()); 3919 if (length == 0) return empty_fixed_array(); 3920 3921 DCHECK(!InNewSpace(filler)); 3922 HeapObject* result = nullptr; 3923 { 3924 AllocationResult allocation = AllocateRawFixedArray(length, pretenure); 3925 if (!allocation.To(&result)) return allocation; 3926 } 3927 3928 result->set_map_no_write_barrier(fixed_array_map()); 3929 FixedArray* array = FixedArray::cast(result); 3930 array->set_length(length); 3931 MemsetPointer(array->data_start(), filler, length); 3932 return array; 3933 } 3934 3935 3936 AllocationResult Heap::AllocateFixedArray(int length, PretenureFlag pretenure) { 3937 return AllocateFixedArrayWithFiller(length, pretenure, undefined_value()); 3938 } 3939 3940 3941 AllocationResult Heap::AllocateUninitializedFixedArray(int length) { 3942 if (length == 0) return empty_fixed_array(); 3943 3944 HeapObject* obj = nullptr; 3945 { 3946 AllocationResult allocation = AllocateRawFixedArray(length, NOT_TENURED); 3947 if (!allocation.To(&obj)) return allocation; 3948 } 3949 3950 obj->set_map_no_write_barrier(fixed_array_map()); 3951 FixedArray::cast(obj)->set_length(length); 3952 return obj; 3953 } 3954 3955 3956 AllocationResult Heap::AllocateUninitializedFixedDoubleArray( 3957 int length, PretenureFlag pretenure) { 3958 if (length == 0) return empty_fixed_array(); 3959 3960 HeapObject* elements = nullptr; 3961 AllocationResult allocation = AllocateRawFixedDoubleArray(length, pretenure); 3962 if (!allocation.To(&elements)) return allocation; 3963 3964 elements->set_map_no_write_barrier(fixed_double_array_map()); 3965 FixedDoubleArray::cast(elements)->set_length(length); 3966 return elements; 3967 } 3968 3969 3970 AllocationResult Heap::AllocateRawFixedDoubleArray(int length, 3971 PretenureFlag pretenure) { 3972 if (length < 0 || length > FixedDoubleArray::kMaxLength) { 3973 v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true); 3974 } 3975 int size = FixedDoubleArray::SizeFor(length); 3976 AllocationSpace space = SelectSpace(pretenure); 3977 3978 HeapObject* object = nullptr; 3979 { 3980 AllocationResult allocation = AllocateRaw(size, space, kDoubleAligned); 3981 if (!allocation.To(&object)) return allocation; 3982 } 3983 3984 return object; 3985 } 3986 3987 3988 AllocationResult Heap::AllocateSymbol() { 3989 // Statically ensure that it is safe to allocate symbols in paged spaces. 3990 STATIC_ASSERT(Symbol::kSize <= kMaxRegularHeapObjectSize); 3991 3992 HeapObject* result = nullptr; 3993 AllocationResult allocation = AllocateRaw(Symbol::kSize, OLD_SPACE); 3994 if (!allocation.To(&result)) return allocation; 3995 3996 result->set_map_no_write_barrier(symbol_map()); 3997 3998 // Generate a random hash value. 3999 int hash = isolate()->GenerateIdentityHash(Name::kHashBitMask); 4000 4001 Symbol::cast(result) 4002 ->set_hash_field(Name::kIsNotArrayIndexMask | (hash << Name::kHashShift)); 4003 Symbol::cast(result)->set_name(undefined_value()); 4004 Symbol::cast(result)->set_flags(0); 4005 4006 DCHECK(!Symbol::cast(result)->is_private()); 4007 return result; 4008 } 4009 4010 4011 AllocationResult Heap::AllocateStruct(InstanceType type) { 4012 Map* map; 4013 switch (type) { 4014 #define MAKE_CASE(NAME, Name, name) \ 4015 case NAME##_TYPE: \ 4016 map = name##_map(); \ 4017 break; 4018 STRUCT_LIST(MAKE_CASE) 4019 #undef MAKE_CASE 4020 default: 4021 UNREACHABLE(); 4022 return exception(); 4023 } 4024 int size = map->instance_size(); 4025 Struct* result = nullptr; 4026 { 4027 AllocationResult allocation = Allocate(map, OLD_SPACE); 4028 if (!allocation.To(&result)) return allocation; 4029 } 4030 result->InitializeBody(size); 4031 return result; 4032 } 4033 4034 4035 bool Heap::IsHeapIterable() { 4036 // TODO(hpayer): This function is not correct. Allocation folding in old 4037 // space breaks the iterability. 4038 return new_space_top_after_last_gc_ == new_space()->top(); 4039 } 4040 4041 4042 void Heap::MakeHeapIterable() { 4043 DCHECK(AllowHeapAllocation::IsAllowed()); 4044 if (!IsHeapIterable()) { 4045 CollectAllGarbage(kMakeHeapIterableMask, 4046 GarbageCollectionReason::kMakeHeapIterable); 4047 } 4048 if (mark_compact_collector()->sweeping_in_progress()) { 4049 mark_compact_collector()->EnsureSweepingCompleted(); 4050 } 4051 DCHECK(IsHeapIterable()); 4052 } 4053 4054 4055 static double ComputeMutatorUtilization(double mutator_speed, double gc_speed) { 4056 const double kMinMutatorUtilization = 0.0; 4057 const double kConservativeGcSpeedInBytesPerMillisecond = 200000; 4058 if (mutator_speed == 0) return kMinMutatorUtilization; 4059 if (gc_speed == 0) gc_speed = kConservativeGcSpeedInBytesPerMillisecond; 4060 // Derivation: 4061 // mutator_utilization = mutator_time / (mutator_time + gc_time) 4062 // mutator_time = 1 / mutator_speed 4063 // gc_time = 1 / gc_speed 4064 // mutator_utilization = (1 / mutator_speed) / 4065 // (1 / mutator_speed + 1 / gc_speed) 4066 // mutator_utilization = gc_speed / (mutator_speed + gc_speed) 4067 return gc_speed / (mutator_speed + gc_speed); 4068 } 4069 4070 4071 double Heap::YoungGenerationMutatorUtilization() { 4072 double mutator_speed = static_cast<double>( 4073 tracer()->NewSpaceAllocationThroughputInBytesPerMillisecond()); 4074 double gc_speed = 4075 tracer()->ScavengeSpeedInBytesPerMillisecond(kForSurvivedObjects); 4076 double result = ComputeMutatorUtilization(mutator_speed, gc_speed); 4077 if (FLAG_trace_mutator_utilization) { 4078 isolate()->PrintWithTimestamp( 4079 "Young generation mutator utilization = %.3f (" 4080 "mutator_speed=%.f, gc_speed=%.f)\n", 4081 result, mutator_speed, gc_speed); 4082 } 4083 return result; 4084 } 4085 4086 4087 double Heap::OldGenerationMutatorUtilization() { 4088 double mutator_speed = static_cast<double>( 4089 tracer()->OldGenerationAllocationThroughputInBytesPerMillisecond()); 4090 double gc_speed = static_cast<double>( 4091 tracer()->CombinedMarkCompactSpeedInBytesPerMillisecond()); 4092 double result = ComputeMutatorUtilization(mutator_speed, gc_speed); 4093 if (FLAG_trace_mutator_utilization) { 4094 isolate()->PrintWithTimestamp( 4095 "Old generation mutator utilization = %.3f (" 4096 "mutator_speed=%.f, gc_speed=%.f)\n", 4097 result, mutator_speed, gc_speed); 4098 } 4099 return result; 4100 } 4101 4102 4103 bool Heap::HasLowYoungGenerationAllocationRate() { 4104 const double high_mutator_utilization = 0.993; 4105 return YoungGenerationMutatorUtilization() > high_mutator_utilization; 4106 } 4107 4108 4109 bool Heap::HasLowOldGenerationAllocationRate() { 4110 const double high_mutator_utilization = 0.993; 4111 return OldGenerationMutatorUtilization() > high_mutator_utilization; 4112 } 4113 4114 4115 bool Heap::HasLowAllocationRate() { 4116 return HasLowYoungGenerationAllocationRate() && 4117 HasLowOldGenerationAllocationRate(); 4118 } 4119 4120 4121 bool Heap::HasHighFragmentation() { 4122 size_t used = PromotedSpaceSizeOfObjects(); 4123 size_t committed = CommittedOldGenerationMemory(); 4124 return HasHighFragmentation(used, committed); 4125 } 4126 4127 bool Heap::HasHighFragmentation(size_t used, size_t committed) { 4128 const size_t kSlack = 16 * MB; 4129 // Fragmentation is high if committed > 2 * used + kSlack. 4130 // Rewrite the exression to avoid overflow. 4131 DCHECK_GE(committed, used); 4132 return committed - used > used + kSlack; 4133 } 4134 4135 bool Heap::ShouldOptimizeForMemoryUsage() { 4136 return FLAG_optimize_for_size || isolate()->IsIsolateInBackground() || 4137 HighMemoryPressure() || IsLowMemoryDevice(); 4138 } 4139 4140 void Heap::ActivateMemoryReducerIfNeeded() { 4141 // Activate memory reducer when switching to background if 4142 // - there was no mark compact since the start. 4143 // - the committed memory can be potentially reduced. 4144 // 2 pages for the old, code, and map space + 1 page for new space. 4145 const int kMinCommittedMemory = 7 * Page::kPageSize; 4146 if (ms_count_ == 0 && CommittedMemory() > kMinCommittedMemory && 4147 isolate()->IsIsolateInBackground()) { 4148 MemoryReducer::Event event; 4149 event.type = MemoryReducer::kPossibleGarbage; 4150 event.time_ms = MonotonicallyIncreasingTimeInMs(); 4151 memory_reducer_->NotifyPossibleGarbage(event); 4152 } 4153 } 4154 4155 void Heap::ReduceNewSpaceSize() { 4156 // TODO(ulan): Unify this constant with the similar constant in 4157 // GCIdleTimeHandler once the change is merged to 4.5. 4158 static const size_t kLowAllocationThroughput = 1000; 4159 const double allocation_throughput = 4160 tracer()->CurrentAllocationThroughputInBytesPerMillisecond(); 4161 4162 if (FLAG_predictable) return; 4163 4164 if (ShouldReduceMemory() || 4165 ((allocation_throughput != 0) && 4166 (allocation_throughput < kLowAllocationThroughput))) { 4167 new_space_->Shrink(); 4168 UncommitFromSpace(); 4169 } 4170 } 4171 4172 bool Heap::MarkingDequesAreEmpty() { 4173 return mark_compact_collector()->marking_deque()->IsEmpty() && 4174 (!UsingEmbedderHeapTracer() || 4175 (wrappers_to_trace() == 0 && 4176 embedder_heap_tracer()->NumberOfWrappersToTrace() == 0)); 4177 } 4178 4179 void Heap::FinalizeIncrementalMarkingIfComplete( 4180 GarbageCollectionReason gc_reason) { 4181 if (incremental_marking()->IsMarking() && 4182 (incremental_marking()->IsReadyToOverApproximateWeakClosure() || 4183 (!incremental_marking()->finalize_marking_completed() && 4184 MarkingDequesAreEmpty()))) { 4185 FinalizeIncrementalMarking(gc_reason); 4186 } else if (incremental_marking()->IsComplete() || MarkingDequesAreEmpty()) { 4187 CollectAllGarbage(current_gc_flags_, gc_reason); 4188 } 4189 } 4190 4191 bool Heap::TryFinalizeIdleIncrementalMarking( 4192 double idle_time_in_ms, GarbageCollectionReason gc_reason) { 4193 size_t size_of_objects = static_cast<size_t>(SizeOfObjects()); 4194 double final_incremental_mark_compact_speed_in_bytes_per_ms = 4195 tracer()->FinalIncrementalMarkCompactSpeedInBytesPerMillisecond(); 4196 if (incremental_marking()->IsReadyToOverApproximateWeakClosure() || 4197 (!incremental_marking()->finalize_marking_completed() && 4198 MarkingDequesAreEmpty() && 4199 gc_idle_time_handler_->ShouldDoOverApproximateWeakClosure( 4200 idle_time_in_ms))) { 4201 FinalizeIncrementalMarking(gc_reason); 4202 return true; 4203 } else if (incremental_marking()->IsComplete() || 4204 (MarkingDequesAreEmpty() && 4205 gc_idle_time_handler_->ShouldDoFinalIncrementalMarkCompact( 4206 idle_time_in_ms, size_of_objects, 4207 final_incremental_mark_compact_speed_in_bytes_per_ms))) { 4208 CollectAllGarbage(current_gc_flags_, gc_reason); 4209 return true; 4210 } 4211 return false; 4212 } 4213 4214 void Heap::RegisterReservationsForBlackAllocation(Reservation* reservations) { 4215 // TODO(hpayer): We do not have to iterate reservations on black objects 4216 // for marking. We just have to execute the special visiting side effect 4217 // code that adds objects to global data structures, e.g. for array buffers. 4218 4219 // Code space, map space, and large object space do not use black pages. 4220 // Hence we have to color all objects of the reservation first black to avoid 4221 // unnecessary marking deque load. 4222 if (incremental_marking()->black_allocation()) { 4223 for (int i = OLD_SPACE; i < Serializer::kNumberOfSpaces; i++) { 4224 const Heap::Reservation& res = reservations[i]; 4225 for (auto& chunk : res) { 4226 Address addr = chunk.start; 4227 while (addr < chunk.end) { 4228 HeapObject* obj = HeapObject::FromAddress(addr); 4229 Marking::MarkBlack(ObjectMarking::MarkBitFrom(obj)); 4230 addr += obj->Size(); 4231 } 4232 } 4233 } 4234 for (int i = OLD_SPACE; i < Serializer::kNumberOfSpaces; i++) { 4235 const Heap::Reservation& res = reservations[i]; 4236 for (auto& chunk : res) { 4237 Address addr = chunk.start; 4238 while (addr < chunk.end) { 4239 HeapObject* obj = HeapObject::FromAddress(addr); 4240 incremental_marking()->IterateBlackObject(obj); 4241 addr += obj->Size(); 4242 } 4243 } 4244 } 4245 } 4246 } 4247 4248 GCIdleTimeHeapState Heap::ComputeHeapState() { 4249 GCIdleTimeHeapState heap_state; 4250 heap_state.contexts_disposed = contexts_disposed_; 4251 heap_state.contexts_disposal_rate = 4252 tracer()->ContextDisposalRateInMilliseconds(); 4253 heap_state.size_of_objects = static_cast<size_t>(SizeOfObjects()); 4254 heap_state.incremental_marking_stopped = incremental_marking()->IsStopped(); 4255 return heap_state; 4256 } 4257 4258 4259 bool Heap::PerformIdleTimeAction(GCIdleTimeAction action, 4260 GCIdleTimeHeapState heap_state, 4261 double deadline_in_ms) { 4262 bool result = false; 4263 switch (action.type) { 4264 case DONE: 4265 result = true; 4266 break; 4267 case DO_INCREMENTAL_STEP: { 4268 const double remaining_idle_time_in_ms = 4269 incremental_marking()->AdvanceIncrementalMarking( 4270 deadline_in_ms, IncrementalMarking::NO_GC_VIA_STACK_GUARD, 4271 IncrementalMarking::FORCE_COMPLETION, StepOrigin::kTask); 4272 if (remaining_idle_time_in_ms > 0.0) { 4273 TryFinalizeIdleIncrementalMarking( 4274 remaining_idle_time_in_ms, 4275 GarbageCollectionReason::kFinalizeMarkingViaTask); 4276 } 4277 result = incremental_marking()->IsStopped(); 4278 break; 4279 } 4280 case DO_FULL_GC: { 4281 DCHECK(contexts_disposed_ > 0); 4282 HistogramTimerScope scope(isolate_->counters()->gc_context()); 4283 TRACE_EVENT0("v8", "V8.GCContext"); 4284 CollectAllGarbage(kNoGCFlags, GarbageCollectionReason::kContextDisposal); 4285 break; 4286 } 4287 case DO_NOTHING: 4288 break; 4289 } 4290 4291 return result; 4292 } 4293 4294 4295 void Heap::IdleNotificationEpilogue(GCIdleTimeAction action, 4296 GCIdleTimeHeapState heap_state, 4297 double start_ms, double deadline_in_ms) { 4298 double idle_time_in_ms = deadline_in_ms - start_ms; 4299 double current_time = MonotonicallyIncreasingTimeInMs(); 4300 last_idle_notification_time_ = current_time; 4301 double deadline_difference = deadline_in_ms - current_time; 4302 4303 contexts_disposed_ = 0; 4304 4305 isolate()->counters()->gc_idle_time_allotted_in_ms()->AddSample( 4306 static_cast<int>(idle_time_in_ms)); 4307 4308 if (deadline_in_ms - start_ms > 4309 GCIdleTimeHandler::kMaxFrameRenderingIdleTime) { 4310 int committed_memory = static_cast<int>(CommittedMemory() / KB); 4311 int used_memory = static_cast<int>(heap_state.size_of_objects / KB); 4312 isolate()->counters()->aggregated_memory_heap_committed()->AddSample( 4313 start_ms, committed_memory); 4314 isolate()->counters()->aggregated_memory_heap_used()->AddSample( 4315 start_ms, used_memory); 4316 } 4317 4318 if (deadline_difference >= 0) { 4319 if (action.type != DONE && action.type != DO_NOTHING) { 4320 isolate()->counters()->gc_idle_time_limit_undershot()->AddSample( 4321 static_cast<int>(deadline_difference)); 4322 } 4323 } else { 4324 isolate()->counters()->gc_idle_time_limit_overshot()->AddSample( 4325 static_cast<int>(-deadline_difference)); 4326 } 4327 4328 if ((FLAG_trace_idle_notification && action.type > DO_NOTHING) || 4329 FLAG_trace_idle_notification_verbose) { 4330 isolate_->PrintWithTimestamp( 4331 "Idle notification: requested idle time %.2f ms, used idle time %.2f " 4332 "ms, deadline usage %.2f ms [", 4333 idle_time_in_ms, idle_time_in_ms - deadline_difference, 4334 deadline_difference); 4335 action.Print(); 4336 PrintF("]"); 4337 if (FLAG_trace_idle_notification_verbose) { 4338 PrintF("["); 4339 heap_state.Print(); 4340 PrintF("]"); 4341 } 4342 PrintF("\n"); 4343 } 4344 } 4345 4346 4347 double Heap::MonotonicallyIncreasingTimeInMs() { 4348 return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() * 4349 static_cast<double>(base::Time::kMillisecondsPerSecond); 4350 } 4351 4352 4353 bool Heap::IdleNotification(int idle_time_in_ms) { 4354 return IdleNotification( 4355 V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() + 4356 (static_cast<double>(idle_time_in_ms) / 4357 static_cast<double>(base::Time::kMillisecondsPerSecond))); 4358 } 4359 4360 4361 bool Heap::IdleNotification(double deadline_in_seconds) { 4362 CHECK(HasBeenSetUp()); 4363 double deadline_in_ms = 4364 deadline_in_seconds * 4365 static_cast<double>(base::Time::kMillisecondsPerSecond); 4366 HistogramTimerScope idle_notification_scope( 4367 isolate_->counters()->gc_idle_notification()); 4368 TRACE_EVENT0("v8", "V8.GCIdleNotification"); 4369 double start_ms = MonotonicallyIncreasingTimeInMs(); 4370 double idle_time_in_ms = deadline_in_ms - start_ms; 4371 4372 tracer()->SampleAllocation(start_ms, NewSpaceAllocationCounter(), 4373 OldGenerationAllocationCounter()); 4374 4375 GCIdleTimeHeapState heap_state = ComputeHeapState(); 4376 4377 GCIdleTimeAction action = 4378 gc_idle_time_handler_->Compute(idle_time_in_ms, heap_state); 4379 4380 bool result = PerformIdleTimeAction(action, heap_state, deadline_in_ms); 4381 4382 IdleNotificationEpilogue(action, heap_state, start_ms, deadline_in_ms); 4383 return result; 4384 } 4385 4386 4387 bool Heap::RecentIdleNotificationHappened() { 4388 return (last_idle_notification_time_ + 4389 GCIdleTimeHandler::kMaxScheduledIdleTime) > 4390 MonotonicallyIncreasingTimeInMs(); 4391 } 4392 4393 class MemoryPressureInterruptTask : public CancelableTask { 4394 public: 4395 explicit MemoryPressureInterruptTask(Heap* heap) 4396 : CancelableTask(heap->isolate()), heap_(heap) {} 4397 4398 virtual ~MemoryPressureInterruptTask() {} 4399 4400 private: 4401 // v8::internal::CancelableTask overrides. 4402 void RunInternal() override { heap_->CheckMemoryPressure(); } 4403 4404 Heap* heap_; 4405 DISALLOW_COPY_AND_ASSIGN(MemoryPressureInterruptTask); 4406 }; 4407 4408 void Heap::CheckMemoryPressure() { 4409 if (HighMemoryPressure()) { 4410 if (isolate()->concurrent_recompilation_enabled()) { 4411 // The optimizing compiler may be unnecessarily holding on to memory. 4412 DisallowHeapAllocation no_recursive_gc; 4413 isolate()->optimizing_compile_dispatcher()->Flush( 4414 OptimizingCompileDispatcher::BlockingBehavior::kDontBlock); 4415 } 4416 } 4417 if (memory_pressure_level_.Value() == MemoryPressureLevel::kCritical) { 4418 CollectGarbageOnMemoryPressure(); 4419 } else if (memory_pressure_level_.Value() == MemoryPressureLevel::kModerate) { 4420 if (FLAG_incremental_marking && incremental_marking()->IsStopped()) { 4421 StartIncrementalMarking(kReduceMemoryFootprintMask, 4422 GarbageCollectionReason::kMemoryPressure); 4423 } 4424 } 4425 MemoryReducer::Event event; 4426 event.type = MemoryReducer::kPossibleGarbage; 4427 event.time_ms = MonotonicallyIncreasingTimeInMs(); 4428 memory_reducer_->NotifyPossibleGarbage(event); 4429 } 4430 4431 void Heap::CollectGarbageOnMemoryPressure() { 4432 const int kGarbageThresholdInBytes = 8 * MB; 4433 const double kGarbageThresholdAsFractionOfTotalMemory = 0.1; 4434 // This constant is the maximum response time in RAIL performance model. 4435 const double kMaxMemoryPressurePauseMs = 100; 4436 4437 double start = MonotonicallyIncreasingTimeInMs(); 4438 CollectAllGarbage(kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, 4439 GarbageCollectionReason::kMemoryPressure, 4440 kGCCallbackFlagCollectAllAvailableGarbage); 4441 double end = MonotonicallyIncreasingTimeInMs(); 4442 4443 // Estimate how much memory we can free. 4444 int64_t potential_garbage = 4445 (CommittedMemory() - SizeOfObjects()) + external_memory_; 4446 // If we can potentially free large amount of memory, then start GC right 4447 // away instead of waiting for memory reducer. 4448 if (potential_garbage >= kGarbageThresholdInBytes && 4449 potential_garbage >= 4450 CommittedMemory() * kGarbageThresholdAsFractionOfTotalMemory) { 4451 // If we spent less than half of the time budget, then perform full GC 4452 // Otherwise, start incremental marking. 4453 if (end - start < kMaxMemoryPressurePauseMs / 2) { 4454 CollectAllGarbage( 4455 kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask, 4456 GarbageCollectionReason::kMemoryPressure, 4457 kGCCallbackFlagCollectAllAvailableGarbage); 4458 } else { 4459 if (FLAG_incremental_marking && incremental_marking()->IsStopped()) { 4460 StartIncrementalMarking(kReduceMemoryFootprintMask, 4461 GarbageCollectionReason::kMemoryPressure); 4462 } 4463 } 4464 } 4465 } 4466 4467 void Heap::MemoryPressureNotification(MemoryPressureLevel level, 4468 bool is_isolate_locked) { 4469 MemoryPressureLevel previous = memory_pressure_level_.Value(); 4470 memory_pressure_level_.SetValue(level); 4471 if ((previous != MemoryPressureLevel::kCritical && 4472 level == MemoryPressureLevel::kCritical) || 4473 (previous == MemoryPressureLevel::kNone && 4474 level == MemoryPressureLevel::kModerate)) { 4475 if (is_isolate_locked) { 4476 CheckMemoryPressure(); 4477 } else { 4478 ExecutionAccess access(isolate()); 4479 isolate()->stack_guard()->RequestGC(); 4480 V8::GetCurrentPlatform()->CallOnForegroundThread( 4481 reinterpret_cast<v8::Isolate*>(isolate()), 4482 new MemoryPressureInterruptTask(this)); 4483 } 4484 } 4485 } 4486 4487 void Heap::CollectCodeStatistics() { 4488 CodeStatistics::ResetCodeAndMetadataStatistics(isolate()); 4489 // We do not look for code in new space, or map space. If code 4490 // somehow ends up in those spaces, we would miss it here. 4491 CodeStatistics::CollectCodeStatistics(code_space_, isolate()); 4492 CodeStatistics::CollectCodeStatistics(old_space_, isolate()); 4493 CodeStatistics::CollectCodeStatistics(lo_space_, isolate()); 4494 } 4495 4496 #ifdef DEBUG 4497 4498 void Heap::Print() { 4499 if (!HasBeenSetUp()) return; 4500 isolate()->PrintStack(stdout); 4501 AllSpaces spaces(this); 4502 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { 4503 space->Print(); 4504 } 4505 } 4506 4507 4508 void Heap::ReportCodeStatistics(const char* title) { 4509 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title); 4510 CollectCodeStatistics(); 4511 CodeStatistics::ReportCodeStatistics(isolate()); 4512 } 4513 4514 4515 // This function expects that NewSpace's allocated objects histogram is 4516 // populated (via a call to CollectStatistics or else as a side effect of a 4517 // just-completed scavenge collection). 4518 void Heap::ReportHeapStatistics(const char* title) { 4519 USE(title); 4520 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n", title, 4521 gc_count_); 4522 PrintF("old_generation_allocation_limit_ %" V8PRIdPTR "\n", 4523 old_generation_allocation_limit_); 4524 4525 PrintF("\n"); 4526 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles(isolate_)); 4527 isolate_->global_handles()->PrintStats(); 4528 PrintF("\n"); 4529 4530 PrintF("Heap statistics : "); 4531 memory_allocator()->ReportStatistics(); 4532 PrintF("To space : "); 4533 new_space_->ReportStatistics(); 4534 PrintF("Old space : "); 4535 old_space_->ReportStatistics(); 4536 PrintF("Code space : "); 4537 code_space_->ReportStatistics(); 4538 PrintF("Map space : "); 4539 map_space_->ReportStatistics(); 4540 PrintF("Large object space : "); 4541 lo_space_->ReportStatistics(); 4542 PrintF(">>>>>> ========================================= >>>>>>\n"); 4543 } 4544 4545 #endif // DEBUG 4546 4547 const char* Heap::GarbageCollectionReasonToString( 4548 GarbageCollectionReason gc_reason) { 4549 switch (gc_reason) { 4550 case GarbageCollectionReason::kAllocationFailure: 4551 return "allocation failure"; 4552 case GarbageCollectionReason::kAllocationLimit: 4553 return "allocation limit"; 4554 case GarbageCollectionReason::kContextDisposal: 4555 return "context disposal"; 4556 case GarbageCollectionReason::kCountersExtension: 4557 return "counters extension"; 4558 case GarbageCollectionReason::kDebugger: 4559 return "debugger"; 4560 case GarbageCollectionReason::kDeserializer: 4561 return "deserialize"; 4562 case GarbageCollectionReason::kExternalMemoryPressure: 4563 return "external memory pressure"; 4564 case GarbageCollectionReason::kFinalizeMarkingViaStackGuard: 4565 return "finalize incremental marking via stack guard"; 4566 case GarbageCollectionReason::kFinalizeMarkingViaTask: 4567 return "finalize incremental marking via task"; 4568 case GarbageCollectionReason::kFullHashtable: 4569 return "full hash-table"; 4570 case GarbageCollectionReason::kHeapProfiler: 4571 return "heap profiler"; 4572 case GarbageCollectionReason::kIdleTask: 4573 return "idle task"; 4574 case GarbageCollectionReason::kLastResort: 4575 return "last resort"; 4576 case GarbageCollectionReason::kLowMemoryNotification: 4577 return "low memory notification"; 4578 case GarbageCollectionReason::kMakeHeapIterable: 4579 return "make heap iterable"; 4580 case GarbageCollectionReason::kMemoryPressure: 4581 return "memory pressure"; 4582 case GarbageCollectionReason::kMemoryReducer: 4583 return "memory reducer"; 4584 case GarbageCollectionReason::kRuntime: 4585 return "runtime"; 4586 case GarbageCollectionReason::kSamplingProfiler: 4587 return "sampling profiler"; 4588 case GarbageCollectionReason::kSnapshotCreator: 4589 return "snapshot creator"; 4590 case GarbageCollectionReason::kTesting: 4591 return "testing"; 4592 case GarbageCollectionReason::kUnknown: 4593 return "unknown"; 4594 } 4595 UNREACHABLE(); 4596 return ""; 4597 } 4598 4599 bool Heap::Contains(HeapObject* value) { 4600 if (memory_allocator()->IsOutsideAllocatedSpace(value->address())) { 4601 return false; 4602 } 4603 return HasBeenSetUp() && 4604 (new_space_->ToSpaceContains(value) || old_space_->Contains(value) || 4605 code_space_->Contains(value) || map_space_->Contains(value) || 4606 lo_space_->Contains(value)); 4607 } 4608 4609 bool Heap::ContainsSlow(Address addr) { 4610 if (memory_allocator()->IsOutsideAllocatedSpace(addr)) { 4611 return false; 4612 } 4613 return HasBeenSetUp() && 4614 (new_space_->ToSpaceContainsSlow(addr) || 4615 old_space_->ContainsSlow(addr) || code_space_->ContainsSlow(addr) || 4616 map_space_->ContainsSlow(addr) || lo_space_->ContainsSlow(addr)); 4617 } 4618 4619 bool Heap::InSpace(HeapObject* value, AllocationSpace space) { 4620 if (memory_allocator()->IsOutsideAllocatedSpace(value->address())) { 4621 return false; 4622 } 4623 if (!HasBeenSetUp()) return false; 4624 4625 switch (space) { 4626 case NEW_SPACE: 4627 return new_space_->ToSpaceContains(value); 4628 case OLD_SPACE: 4629 return old_space_->Contains(value); 4630 case CODE_SPACE: 4631 return code_space_->Contains(value); 4632 case MAP_SPACE: 4633 return map_space_->Contains(value); 4634 case LO_SPACE: 4635 return lo_space_->Contains(value); 4636 } 4637 UNREACHABLE(); 4638 return false; 4639 } 4640 4641 bool Heap::InSpaceSlow(Address addr, AllocationSpace space) { 4642 if (memory_allocator()->IsOutsideAllocatedSpace(addr)) { 4643 return false; 4644 } 4645 if (!HasBeenSetUp()) return false; 4646 4647 switch (space) { 4648 case NEW_SPACE: 4649 return new_space_->ToSpaceContainsSlow(addr); 4650 case OLD_SPACE: 4651 return old_space_->ContainsSlow(addr); 4652 case CODE_SPACE: 4653 return code_space_->ContainsSlow(addr); 4654 case MAP_SPACE: 4655 return map_space_->ContainsSlow(addr); 4656 case LO_SPACE: 4657 return lo_space_->ContainsSlow(addr); 4658 } 4659 UNREACHABLE(); 4660 return false; 4661 } 4662 4663 4664 bool Heap::IsValidAllocationSpace(AllocationSpace space) { 4665 switch (space) { 4666 case NEW_SPACE: 4667 case OLD_SPACE: 4668 case CODE_SPACE: 4669 case MAP_SPACE: 4670 case LO_SPACE: 4671 return true; 4672 default: 4673 return false; 4674 } 4675 } 4676 4677 4678 bool Heap::RootIsImmortalImmovable(int root_index) { 4679 switch (root_index) { 4680 #define IMMORTAL_IMMOVABLE_ROOT(name) case Heap::k##name##RootIndex: 4681 IMMORTAL_IMMOVABLE_ROOT_LIST(IMMORTAL_IMMOVABLE_ROOT) 4682 #undef IMMORTAL_IMMOVABLE_ROOT 4683 #define INTERNALIZED_STRING(name, value) case Heap::k##name##RootIndex: 4684 INTERNALIZED_STRING_LIST(INTERNALIZED_STRING) 4685 #undef INTERNALIZED_STRING 4686 #define STRING_TYPE(NAME, size, name, Name) case Heap::k##Name##MapRootIndex: 4687 STRING_TYPE_LIST(STRING_TYPE) 4688 #undef STRING_TYPE 4689 return true; 4690 default: 4691 return false; 4692 } 4693 } 4694 4695 4696 #ifdef VERIFY_HEAP 4697 void Heap::Verify() { 4698 CHECK(HasBeenSetUp()); 4699 HandleScope scope(isolate()); 4700 4701 if (mark_compact_collector()->sweeping_in_progress()) { 4702 // We have to wait here for the sweeper threads to have an iterable heap. 4703 mark_compact_collector()->EnsureSweepingCompleted(); 4704 } 4705 4706 VerifyPointersVisitor visitor; 4707 IterateRoots(&visitor, VISIT_ONLY_STRONG); 4708 4709 VerifySmisVisitor smis_visitor; 4710 IterateSmiRoots(&smis_visitor); 4711 4712 new_space_->Verify(); 4713 4714 old_space_->Verify(&visitor); 4715 map_space_->Verify(&visitor); 4716 4717 VerifyPointersVisitor no_dirty_regions_visitor; 4718 code_space_->Verify(&no_dirty_regions_visitor); 4719 4720 lo_space_->Verify(); 4721 4722 mark_compact_collector()->VerifyWeakEmbeddedObjectsInCode(); 4723 if (FLAG_omit_map_checks_for_leaf_maps) { 4724 mark_compact_collector()->VerifyOmittedMapChecks(); 4725 } 4726 } 4727 #endif 4728 4729 4730 void Heap::ZapFromSpace() { 4731 if (!new_space_->IsFromSpaceCommitted()) return; 4732 for (Page* page : NewSpacePageRange(new_space_->FromSpaceStart(), 4733 new_space_->FromSpaceEnd())) { 4734 for (Address cursor = page->area_start(), limit = page->area_end(); 4735 cursor < limit; cursor += kPointerSize) { 4736 Memory::Address_at(cursor) = kFromSpaceZapValue; 4737 } 4738 } 4739 } 4740 4741 class IterateAndScavengePromotedObjectsVisitor final : public ObjectVisitor { 4742 public: 4743 IterateAndScavengePromotedObjectsVisitor(Heap* heap, HeapObject* target, 4744 bool record_slots) 4745 : heap_(heap), target_(target), record_slots_(record_slots) {} 4746 4747 inline void VisitPointers(Object** start, Object** end) override { 4748 Address slot_address = reinterpret_cast<Address>(start); 4749 Page* page = Page::FromAddress(slot_address); 4750 4751 while (slot_address < reinterpret_cast<Address>(end)) { 4752 Object** slot = reinterpret_cast<Object**>(slot_address); 4753 Object* target = *slot; 4754 4755 if (target->IsHeapObject()) { 4756 if (heap_->InFromSpace(target)) { 4757 Scavenger::ScavengeObject(reinterpret_cast<HeapObject**>(slot), 4758 HeapObject::cast(target)); 4759 target = *slot; 4760 if (heap_->InNewSpace(target)) { 4761 SLOW_DCHECK(heap_->InToSpace(target)); 4762 SLOW_DCHECK(target->IsHeapObject()); 4763 RememberedSet<OLD_TO_NEW>::Insert(page, slot_address); 4764 } 4765 SLOW_DCHECK(!MarkCompactCollector::IsOnEvacuationCandidate( 4766 HeapObject::cast(target))); 4767 } else if (record_slots_ && 4768 MarkCompactCollector::IsOnEvacuationCandidate( 4769 HeapObject::cast(target))) { 4770 heap_->mark_compact_collector()->RecordSlot(target_, slot, target); 4771 } 4772 } 4773 4774 slot_address += kPointerSize; 4775 } 4776 } 4777 4778 inline void VisitCodeEntry(Address code_entry_slot) override { 4779 // Black allocation requires us to process objects referenced by 4780 // promoted objects. 4781 if (heap_->incremental_marking()->black_allocation()) { 4782 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot)); 4783 IncrementalMarking::MarkGrey(heap_, code); 4784 } 4785 } 4786 4787 private: 4788 Heap* heap_; 4789 HeapObject* target_; 4790 bool record_slots_; 4791 }; 4792 4793 void Heap::IterateAndScavengePromotedObject(HeapObject* target, int size, 4794 bool was_marked_black) { 4795 // We are not collecting slots on new space objects during mutation 4796 // thus we have to scan for pointers to evacuation candidates when we 4797 // promote objects. But we should not record any slots in non-black 4798 // objects. Grey object's slots would be rescanned. 4799 // White object might not survive until the end of collection 4800 // it would be a violation of the invariant to record it's slots. 4801 bool record_slots = false; 4802 if (incremental_marking()->IsCompacting()) { 4803 MarkBit mark_bit = ObjectMarking::MarkBitFrom(target); 4804 record_slots = Marking::IsBlack(mark_bit); 4805 } 4806 4807 IterateAndScavengePromotedObjectsVisitor visitor(this, target, record_slots); 4808 if (target->IsJSFunction()) { 4809 // JSFunctions reachable through kNextFunctionLinkOffset are weak. Slots for 4810 // this links are recorded during processing of weak lists. 4811 JSFunction::BodyDescriptorWeakCode::IterateBody(target, size, &visitor); 4812 } else { 4813 target->IterateBody(target->map()->instance_type(), size, &visitor); 4814 } 4815 4816 // When black allocations is on, we have to visit not already marked black 4817 // objects (in new space) promoted to black pages to keep their references 4818 // alive. 4819 // TODO(hpayer): Implement a special promotion visitor that incorporates 4820 // regular visiting and IteratePromotedObjectPointers. 4821 if (!was_marked_black) { 4822 if (incremental_marking()->black_allocation()) { 4823 IncrementalMarking::MarkGrey(this, target->map()); 4824 incremental_marking()->IterateBlackObject(target); 4825 } 4826 } 4827 } 4828 4829 4830 void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) { 4831 IterateStrongRoots(v, mode); 4832 IterateWeakRoots(v, mode); 4833 } 4834 4835 4836 void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { 4837 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kStringTableRootIndex])); 4838 v->Synchronize(VisitorSynchronization::kStringTable); 4839 if (mode != VISIT_ALL_IN_SCAVENGE && mode != VISIT_ALL_IN_SWEEP_NEWSPACE) { 4840 // Scavenge collections have special processing for this. 4841 external_string_table_.Iterate(v); 4842 } 4843 v->Synchronize(VisitorSynchronization::kExternalStringsTable); 4844 } 4845 4846 4847 void Heap::IterateSmiRoots(ObjectVisitor* v) { 4848 // Acquire execution access since we are going to read stack limit values. 4849 ExecutionAccess access(isolate()); 4850 v->VisitPointers(&roots_[kSmiRootsStart], &roots_[kRootListLength]); 4851 v->Synchronize(VisitorSynchronization::kSmiRootList); 4852 } 4853 4854 // We cannot avoid stale handles to left-trimmed objects, but can only make 4855 // sure all handles still needed are updated. Filter out a stale pointer 4856 // and clear the slot to allow post processing of handles (needed because 4857 // the sweeper might actually free the underlying page). 4858 class FixStaleLeftTrimmedHandlesVisitor : public ObjectVisitor { 4859 public: 4860 explicit FixStaleLeftTrimmedHandlesVisitor(Heap* heap) : heap_(heap) { 4861 USE(heap_); 4862 } 4863 4864 void VisitPointer(Object** p) override { FixHandle(p); } 4865 4866 void VisitPointers(Object** start, Object** end) override { 4867 for (Object** p = start; p < end; p++) FixHandle(p); 4868 } 4869 4870 private: 4871 inline void FixHandle(Object** p) { 4872 HeapObject* current = reinterpret_cast<HeapObject*>(*p); 4873 if (!current->IsHeapObject()) return; 4874 const MapWord map_word = current->map_word(); 4875 if (!map_word.IsForwardingAddress() && current->IsFiller()) { 4876 #ifdef DEBUG 4877 // We need to find a FixedArrayBase map after walking the fillers. 4878 while (current->IsFiller()) { 4879 Address next = reinterpret_cast<Address>(current); 4880 if (current->map() == heap_->one_pointer_filler_map()) { 4881 next += kPointerSize; 4882 } else if (current->map() == heap_->two_pointer_filler_map()) { 4883 next += 2 * kPointerSize; 4884 } else { 4885 next += current->Size(); 4886 } 4887 current = reinterpret_cast<HeapObject*>(next); 4888 } 4889 DCHECK(current->IsFixedArrayBase()); 4890 #endif // DEBUG 4891 *p = nullptr; 4892 } 4893 } 4894 4895 Heap* heap_; 4896 }; 4897 4898 void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { 4899 v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]); 4900 v->Synchronize(VisitorSynchronization::kStrongRootList); 4901 // The serializer/deserializer iterates the root list twice, first to pick 4902 // off immortal immovable roots to make sure they end up on the first page, 4903 // and then again for the rest. 4904 if (mode == VISIT_ONLY_STRONG_ROOT_LIST) return; 4905 4906 isolate_->bootstrapper()->Iterate(v); 4907 v->Synchronize(VisitorSynchronization::kBootstrapper); 4908 isolate_->Iterate(v); 4909 v->Synchronize(VisitorSynchronization::kTop); 4910 Relocatable::Iterate(isolate_, v); 4911 v->Synchronize(VisitorSynchronization::kRelocatable); 4912 isolate_->debug()->Iterate(v); 4913 v->Synchronize(VisitorSynchronization::kDebug); 4914 4915 isolate_->compilation_cache()->Iterate(v); 4916 v->Synchronize(VisitorSynchronization::kCompilationCache); 4917 4918 // Iterate over local handles in handle scopes. 4919 FixStaleLeftTrimmedHandlesVisitor left_trim_visitor(this); 4920 isolate_->handle_scope_implementer()->Iterate(&left_trim_visitor); 4921 isolate_->handle_scope_implementer()->Iterate(v); 4922 isolate_->IterateDeferredHandles(v); 4923 v->Synchronize(VisitorSynchronization::kHandleScope); 4924 4925 // Iterate over the builtin code objects and code stubs in the 4926 // heap. Note that it is not necessary to iterate over code objects 4927 // on scavenge collections. 4928 if (mode != VISIT_ALL_IN_SCAVENGE) { 4929 isolate_->builtins()->IterateBuiltins(v); 4930 v->Synchronize(VisitorSynchronization::kBuiltins); 4931 isolate_->interpreter()->IterateDispatchTable(v); 4932 v->Synchronize(VisitorSynchronization::kDispatchTable); 4933 } 4934 4935 // Iterate over global handles. 4936 switch (mode) { 4937 case VISIT_ONLY_STRONG_ROOT_LIST: 4938 UNREACHABLE(); 4939 break; 4940 case VISIT_ONLY_STRONG: 4941 case VISIT_ONLY_STRONG_FOR_SERIALIZATION: 4942 isolate_->global_handles()->IterateStrongRoots(v); 4943 break; 4944 case VISIT_ALL_IN_SCAVENGE: 4945 isolate_->global_handles()->IterateNewSpaceStrongAndDependentRoots(v); 4946 break; 4947 case VISIT_ALL_IN_SWEEP_NEWSPACE: 4948 case VISIT_ALL: 4949 isolate_->global_handles()->IterateAllRoots(v); 4950 break; 4951 } 4952 v->Synchronize(VisitorSynchronization::kGlobalHandles); 4953 4954 // Iterate over eternal handles. 4955 if (mode == VISIT_ALL_IN_SCAVENGE) { 4956 isolate_->eternal_handles()->IterateNewSpaceRoots(v); 4957 } else { 4958 isolate_->eternal_handles()->IterateAllRoots(v); 4959 } 4960 v->Synchronize(VisitorSynchronization::kEternalHandles); 4961 4962 // Iterate over pointers being held by inactive threads. 4963 isolate_->thread_manager()->Iterate(v); 4964 v->Synchronize(VisitorSynchronization::kThreadManager); 4965 4966 // Iterate over other strong roots (currently only identity maps). 4967 for (StrongRootsList* list = strong_roots_list_; list; list = list->next) { 4968 v->VisitPointers(list->start, list->end); 4969 } 4970 v->Synchronize(VisitorSynchronization::kStrongRoots); 4971 4972 // Iterate over the partial snapshot cache unless serializing. 4973 if (mode != VISIT_ONLY_STRONG_FOR_SERIALIZATION) { 4974 SerializerDeserializer::Iterate(isolate_, v); 4975 } 4976 // We don't do a v->Synchronize call here, because in debug mode that will 4977 // output a flag to the snapshot. However at this point the serializer and 4978 // deserializer are deliberately a little unsynchronized (see above) so the 4979 // checking of the sync flag in the snapshot would fail. 4980 } 4981 4982 4983 // TODO(1236194): Since the heap size is configurable on the command line 4984 // and through the API, we should gracefully handle the case that the heap 4985 // size is not big enough to fit all the initial objects. 4986 bool Heap::ConfigureHeap(size_t max_semi_space_size, size_t max_old_space_size, 4987 size_t max_executable_size, size_t code_range_size) { 4988 if (HasBeenSetUp()) return false; 4989 4990 // Overwrite default configuration. 4991 if (max_semi_space_size != 0) { 4992 max_semi_space_size_ = max_semi_space_size * MB; 4993 } 4994 if (max_old_space_size != 0) { 4995 max_old_generation_size_ = max_old_space_size * MB; 4996 } 4997 if (max_executable_size != 0) { 4998 max_executable_size_ = max_executable_size * MB; 4999 } 5000 5001 // If max space size flags are specified overwrite the configuration. 5002 if (FLAG_max_semi_space_size > 0) { 5003 max_semi_space_size_ = static_cast<size_t>(FLAG_max_semi_space_size) * MB; 5004 } 5005 if (FLAG_max_old_space_size > 0) { 5006 max_old_generation_size_ = 5007 static_cast<size_t>(FLAG_max_old_space_size) * MB; 5008 } 5009 if (FLAG_max_executable_size > 0) { 5010 max_executable_size_ = static_cast<size_t>(FLAG_max_executable_size) * MB; 5011 } 5012 5013 if (Page::kPageSize > MB) { 5014 max_semi_space_size_ = ROUND_UP(max_semi_space_size_, Page::kPageSize); 5015 max_old_generation_size_ = 5016 ROUND_UP(max_old_generation_size_, Page::kPageSize); 5017 max_executable_size_ = ROUND_UP(max_executable_size_, Page::kPageSize); 5018 } 5019 5020 if (FLAG_stress_compaction) { 5021 // This will cause more frequent GCs when stressing. 5022 max_semi_space_size_ = MB; 5023 } 5024 5025 // The new space size must be a power of two to support single-bit testing 5026 // for containment. 5027 max_semi_space_size_ = base::bits::RoundUpToPowerOfTwo32( 5028 static_cast<uint32_t>(max_semi_space_size_)); 5029 5030 if (FLAG_min_semi_space_size > 0) { 5031 size_t initial_semispace_size = 5032 static_cast<size_t>(FLAG_min_semi_space_size) * MB; 5033 if (initial_semispace_size > max_semi_space_size_) { 5034 initial_semispace_size_ = max_semi_space_size_; 5035 if (FLAG_trace_gc) { 5036 PrintIsolate(isolate_, 5037 "Min semi-space size cannot be more than the maximum " 5038 "semi-space size of %" PRIuS " MB\n", 5039 max_semi_space_size_ / MB); 5040 } 5041 } else { 5042 initial_semispace_size_ = 5043 ROUND_UP(initial_semispace_size, Page::kPageSize); 5044 } 5045 } 5046 5047 initial_semispace_size_ = Min(initial_semispace_size_, max_semi_space_size_); 5048 5049 if (FLAG_semi_space_growth_factor < 2) { 5050 FLAG_semi_space_growth_factor = 2; 5051 } 5052 5053 // The old generation is paged and needs at least one page for each space. 5054 int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1; 5055 max_old_generation_size_ = 5056 Max(static_cast<size_t>(paged_space_count * Page::kPageSize), 5057 max_old_generation_size_); 5058 5059 // The max executable size must be less than or equal to the max old 5060 // generation size. 5061 if (max_executable_size_ > max_old_generation_size_) { 5062 max_executable_size_ = max_old_generation_size_; 5063 } 5064 5065 if (FLAG_initial_old_space_size > 0) { 5066 initial_old_generation_size_ = FLAG_initial_old_space_size * MB; 5067 } else { 5068 initial_old_generation_size_ = 5069 max_old_generation_size_ / kInitalOldGenerationLimitFactor; 5070 } 5071 old_generation_allocation_limit_ = initial_old_generation_size_; 5072 5073 // We rely on being able to allocate new arrays in paged spaces. 5074 DCHECK(kMaxRegularHeapObjectSize >= 5075 (JSArray::kSize + 5076 FixedArray::SizeFor(JSArray::kInitialMaxFastElementArray) + 5077 AllocationMemento::kSize)); 5078 5079 code_range_size_ = code_range_size * MB; 5080 5081 configured_ = true; 5082 return true; 5083 } 5084 5085 5086 void Heap::AddToRingBuffer(const char* string) { 5087 size_t first_part = 5088 Min(strlen(string), kTraceRingBufferSize - ring_buffer_end_); 5089 memcpy(trace_ring_buffer_ + ring_buffer_end_, string, first_part); 5090 ring_buffer_end_ += first_part; 5091 if (first_part < strlen(string)) { 5092 ring_buffer_full_ = true; 5093 size_t second_part = strlen(string) - first_part; 5094 memcpy(trace_ring_buffer_, string + first_part, second_part); 5095 ring_buffer_end_ = second_part; 5096 } 5097 } 5098 5099 5100 void Heap::GetFromRingBuffer(char* buffer) { 5101 size_t copied = 0; 5102 if (ring_buffer_full_) { 5103 copied = kTraceRingBufferSize - ring_buffer_end_; 5104 memcpy(buffer, trace_ring_buffer_ + ring_buffer_end_, copied); 5105 } 5106 memcpy(buffer + copied, trace_ring_buffer_, ring_buffer_end_); 5107 } 5108 5109 5110 bool Heap::ConfigureHeapDefault() { return ConfigureHeap(0, 0, 0, 0); } 5111 5112 5113 void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { 5114 *stats->start_marker = HeapStats::kStartMarker; 5115 *stats->end_marker = HeapStats::kEndMarker; 5116 *stats->new_space_size = new_space_->Size(); 5117 *stats->new_space_capacity = new_space_->Capacity(); 5118 *stats->old_space_size = old_space_->SizeOfObjects(); 5119 *stats->old_space_capacity = old_space_->Capacity(); 5120 *stats->code_space_size = code_space_->SizeOfObjects(); 5121 *stats->code_space_capacity = code_space_->Capacity(); 5122 *stats->map_space_size = map_space_->SizeOfObjects(); 5123 *stats->map_space_capacity = map_space_->Capacity(); 5124 *stats->lo_space_size = lo_space_->Size(); 5125 isolate_->global_handles()->RecordStats(stats); 5126 *stats->memory_allocator_size = memory_allocator()->Size(); 5127 *stats->memory_allocator_capacity = 5128 memory_allocator()->Size() + memory_allocator()->Available(); 5129 *stats->os_error = base::OS::GetLastError(); 5130 *stats->malloced_memory = isolate_->allocator()->GetCurrentMemoryUsage(); 5131 *stats->malloced_peak_memory = isolate_->allocator()->GetMaxMemoryUsage(); 5132 if (take_snapshot) { 5133 HeapIterator iterator(this); 5134 for (HeapObject* obj = iterator.next(); obj != NULL; 5135 obj = iterator.next()) { 5136 InstanceType type = obj->map()->instance_type(); 5137 DCHECK(0 <= type && type <= LAST_TYPE); 5138 stats->objects_per_type[type]++; 5139 stats->size_per_type[type] += obj->Size(); 5140 } 5141 } 5142 if (stats->last_few_messages != NULL) 5143 GetFromRingBuffer(stats->last_few_messages); 5144 if (stats->js_stacktrace != NULL) { 5145 FixedStringAllocator fixed(stats->js_stacktrace, kStacktraceBufferSize - 1); 5146 StringStream accumulator(&fixed, StringStream::kPrintObjectConcise); 5147 if (gc_state() == Heap::NOT_IN_GC) { 5148 isolate()->PrintStack(&accumulator, Isolate::kPrintStackVerbose); 5149 } else { 5150 accumulator.Add("Cannot get stack trace in GC."); 5151 } 5152 } 5153 } 5154 5155 size_t Heap::PromotedSpaceSizeOfObjects() { 5156 return old_space_->SizeOfObjects() + code_space_->SizeOfObjects() + 5157 map_space_->SizeOfObjects() + lo_space_->SizeOfObjects(); 5158 } 5159 5160 uint64_t Heap::PromotedExternalMemorySize() { 5161 if (external_memory_ <= external_memory_at_last_mark_compact_) return 0; 5162 return static_cast<uint64_t>(external_memory_ - 5163 external_memory_at_last_mark_compact_); 5164 } 5165 5166 5167 const double Heap::kMinHeapGrowingFactor = 1.1; 5168 const double Heap::kMaxHeapGrowingFactor = 4.0; 5169 const double Heap::kMaxHeapGrowingFactorMemoryConstrained = 2.0; 5170 const double Heap::kMaxHeapGrowingFactorIdle = 1.5; 5171 const double Heap::kConservativeHeapGrowingFactor = 1.3; 5172 const double Heap::kTargetMutatorUtilization = 0.97; 5173 5174 5175 // Given GC speed in bytes per ms, the allocation throughput in bytes per ms 5176 // (mutator speed), this function returns the heap growing factor that will 5177 // achieve the kTargetMutatorUtilisation if the GC speed and the mutator speed 5178 // remain the same until the next GC. 5179 // 5180 // For a fixed time-frame T = TM + TG, the mutator utilization is the ratio 5181 // TM / (TM + TG), where TM is the time spent in the mutator and TG is the 5182 // time spent in the garbage collector. 5183 // 5184 // Let MU be kTargetMutatorUtilisation, the desired mutator utilization for the 5185 // time-frame from the end of the current GC to the end of the next GC. Based 5186 // on the MU we can compute the heap growing factor F as 5187 // 5188 // F = R * (1 - MU) / (R * (1 - MU) - MU), where R = gc_speed / mutator_speed. 5189 // 5190 // This formula can be derived as follows. 5191 // 5192 // F = Limit / Live by definition, where the Limit is the allocation limit, 5193 // and the Live is size of live objects. 5194 // Lets assume that we already know the Limit. Then: 5195 // TG = Limit / gc_speed 5196 // TM = (TM + TG) * MU, by definition of MU. 5197 // TM = TG * MU / (1 - MU) 5198 // TM = Limit * MU / (gc_speed * (1 - MU)) 5199 // On the other hand, if the allocation throughput remains constant: 5200 // Limit = Live + TM * allocation_throughput = Live + TM * mutator_speed 5201 // Solving it for TM, we get 5202 // TM = (Limit - Live) / mutator_speed 5203 // Combining the two equation for TM: 5204 // (Limit - Live) / mutator_speed = Limit * MU / (gc_speed * (1 - MU)) 5205 // (Limit - Live) = Limit * MU * mutator_speed / (gc_speed * (1 - MU)) 5206 // substitute R = gc_speed / mutator_speed 5207 // (Limit - Live) = Limit * MU / (R * (1 - MU)) 5208 // substitute F = Limit / Live 5209 // F - 1 = F * MU / (R * (1 - MU)) 5210 // F - F * MU / (R * (1 - MU)) = 1 5211 // F * (1 - MU / (R * (1 - MU))) = 1 5212 // F * (R * (1 - MU) - MU) / (R * (1 - MU)) = 1 5213 // F = R * (1 - MU) / (R * (1 - MU) - MU) 5214 double Heap::HeapGrowingFactor(double gc_speed, double mutator_speed) { 5215 if (gc_speed == 0 || mutator_speed == 0) return kMaxHeapGrowingFactor; 5216 5217 const double speed_ratio = gc_speed / mutator_speed; 5218 const double mu = kTargetMutatorUtilization; 5219 5220 const double a = speed_ratio * (1 - mu); 5221 const double b = speed_ratio * (1 - mu) - mu; 5222 5223 // The factor is a / b, but we need to check for small b first. 5224 double factor = 5225 (a < b * kMaxHeapGrowingFactor) ? a / b : kMaxHeapGrowingFactor; 5226 factor = Min(factor, kMaxHeapGrowingFactor); 5227 factor = Max(factor, kMinHeapGrowingFactor); 5228 return factor; 5229 } 5230 5231 size_t Heap::CalculateOldGenerationAllocationLimit(double factor, 5232 size_t old_gen_size) { 5233 CHECK(factor > 1.0); 5234 CHECK(old_gen_size > 0); 5235 uint64_t limit = static_cast<uint64_t>(old_gen_size * factor); 5236 limit = Max(limit, static_cast<uint64_t>(old_gen_size) + 5237 MinimumAllocationLimitGrowingStep()); 5238 limit += new_space_->Capacity(); 5239 uint64_t halfway_to_the_max = 5240 (static_cast<uint64_t>(old_gen_size) + max_old_generation_size_) / 2; 5241 return static_cast<size_t>(Min(limit, halfway_to_the_max)); 5242 } 5243 5244 size_t Heap::MinimumAllocationLimitGrowingStep() { 5245 const size_t kRegularAllocationLimitGrowingStep = 8; 5246 const size_t kLowMemoryAllocationLimitGrowingStep = 2; 5247 size_t limit = (Page::kPageSize > MB ? Page::kPageSize : MB); 5248 return limit * (ShouldOptimizeForMemoryUsage() 5249 ? kLowMemoryAllocationLimitGrowingStep 5250 : kRegularAllocationLimitGrowingStep); 5251 } 5252 5253 void Heap::SetOldGenerationAllocationLimit(size_t old_gen_size, double gc_speed, 5254 double mutator_speed) { 5255 double factor = HeapGrowingFactor(gc_speed, mutator_speed); 5256 5257 if (FLAG_trace_gc_verbose) { 5258 isolate_->PrintWithTimestamp( 5259 "Heap growing factor %.1f based on mu=%.3f, speed_ratio=%.f " 5260 "(gc=%.f, mutator=%.f)\n", 5261 factor, kTargetMutatorUtilization, gc_speed / mutator_speed, gc_speed, 5262 mutator_speed); 5263 } 5264 5265 if (IsMemoryConstrainedDevice()) { 5266 factor = Min(factor, kMaxHeapGrowingFactorMemoryConstrained); 5267 } 5268 5269 if (memory_reducer_->ShouldGrowHeapSlowly() || 5270 ShouldOptimizeForMemoryUsage()) { 5271 factor = Min(factor, kConservativeHeapGrowingFactor); 5272 } 5273 5274 if (FLAG_stress_compaction || ShouldReduceMemory()) { 5275 factor = kMinHeapGrowingFactor; 5276 } 5277 5278 if (FLAG_heap_growing_percent > 0) { 5279 factor = 1.0 + FLAG_heap_growing_percent / 100.0; 5280 } 5281 5282 old_generation_allocation_limit_ = 5283 CalculateOldGenerationAllocationLimit(factor, old_gen_size); 5284 5285 if (FLAG_trace_gc_verbose) { 5286 isolate_->PrintWithTimestamp( 5287 "Grow: old size: %" PRIuS " KB, new limit: %" PRIuS " KB (%.1f)\n", 5288 old_gen_size / KB, old_generation_allocation_limit_ / KB, factor); 5289 } 5290 } 5291 5292 void Heap::DampenOldGenerationAllocationLimit(size_t old_gen_size, 5293 double gc_speed, 5294 double mutator_speed) { 5295 double factor = HeapGrowingFactor(gc_speed, mutator_speed); 5296 size_t limit = CalculateOldGenerationAllocationLimit(factor, old_gen_size); 5297 if (limit < old_generation_allocation_limit_) { 5298 if (FLAG_trace_gc_verbose) { 5299 isolate_->PrintWithTimestamp( 5300 "Dampen: old size: %" PRIuS " KB, old limit: %" PRIuS 5301 " KB, " 5302 "new limit: %" PRIuS " KB (%.1f)\n", 5303 old_gen_size / KB, old_generation_allocation_limit_ / KB, limit / KB, 5304 factor); 5305 } 5306 old_generation_allocation_limit_ = limit; 5307 } 5308 } 5309 5310 // This predicate is called when an old generation space cannot allocated from 5311 // the free list and is about to add a new page. Returning false will cause a 5312 // major GC. It happens when the old generation allocation limit is reached and 5313 // - either we need to optimize for memory usage, 5314 // - or the incremental marking is not in progress and we cannot start it. 5315 bool Heap::ShouldExpandOldGenerationOnSlowAllocation() { 5316 if (always_allocate() || OldGenerationSpaceAvailable() > 0) return true; 5317 // We reached the old generation allocation limit. 5318 5319 if (ShouldOptimizeForMemoryUsage()) return false; 5320 5321 if (incremental_marking()->NeedsFinalization()) { 5322 return !AllocationLimitOvershotByLargeMargin(); 5323 } 5324 5325 if (incremental_marking()->IsStopped() && 5326 IncrementalMarkingLimitReached() == IncrementalMarkingLimit::kNoLimit) { 5327 // We cannot start incremental marking. 5328 return false; 5329 } 5330 return true; 5331 } 5332 5333 // This function returns either kNoLimit, kSoftLimit, or kHardLimit. 5334 // The kNoLimit means that either incremental marking is disabled or it is too 5335 // early to start incremental marking. 5336 // The kSoftLimit means that incremental marking should be started soon. 5337 // The kHardLimit means that incremental marking should be started immediately. 5338 Heap::IncrementalMarkingLimit Heap::IncrementalMarkingLimitReached() { 5339 if (!incremental_marking()->CanBeActivated() || 5340 PromotedSpaceSizeOfObjects() <= 5341 IncrementalMarking::kActivationThreshold) { 5342 // Incremental marking is disabled or it is too early to start. 5343 return IncrementalMarkingLimit::kNoLimit; 5344 } 5345 if ((FLAG_stress_compaction && (gc_count_ & 1) != 0) || 5346 HighMemoryPressure()) { 5347 // If there is high memory pressure or stress testing is enabled, then 5348 // start marking immediately. 5349 return IncrementalMarkingLimit::kHardLimit; 5350 } 5351 size_t old_generation_space_available = OldGenerationSpaceAvailable(); 5352 if (old_generation_space_available > new_space_->Capacity()) { 5353 return IncrementalMarkingLimit::kNoLimit; 5354 } 5355 // We are close to the allocation limit. 5356 // Choose between the hard and the soft limits. 5357 if (old_generation_space_available == 0 || ShouldOptimizeForMemoryUsage()) { 5358 return IncrementalMarkingLimit::kHardLimit; 5359 } 5360 return IncrementalMarkingLimit::kSoftLimit; 5361 } 5362 5363 void Heap::EnableInlineAllocation() { 5364 if (!inline_allocation_disabled_) return; 5365 inline_allocation_disabled_ = false; 5366 5367 // Update inline allocation limit for new space. 5368 new_space()->UpdateInlineAllocationLimit(0); 5369 } 5370 5371 5372 void Heap::DisableInlineAllocation() { 5373 if (inline_allocation_disabled_) return; 5374 inline_allocation_disabled_ = true; 5375 5376 // Update inline allocation limit for new space. 5377 new_space()->UpdateInlineAllocationLimit(0); 5378 5379 // Update inline allocation limit for old spaces. 5380 PagedSpaces spaces(this); 5381 for (PagedSpace* space = spaces.next(); space != NULL; 5382 space = spaces.next()) { 5383 space->EmptyAllocationInfo(); 5384 } 5385 } 5386 5387 5388 V8_DECLARE_ONCE(initialize_gc_once); 5389 5390 static void InitializeGCOnce() { 5391 Scavenger::Initialize(); 5392 StaticScavengeVisitor::Initialize(); 5393 MarkCompactCollector::Initialize(); 5394 } 5395 5396 5397 bool Heap::SetUp() { 5398 #ifdef DEBUG 5399 allocation_timeout_ = FLAG_gc_interval; 5400 #endif 5401 5402 // Initialize heap spaces and initial maps and objects. Whenever something 5403 // goes wrong, just return false. The caller should check the results and 5404 // call Heap::TearDown() to release allocated memory. 5405 // 5406 // If the heap is not yet configured (e.g. through the API), configure it. 5407 // Configuration is based on the flags new-space-size (really the semispace 5408 // size) and old-space-size if set or the initial values of semispace_size_ 5409 // and old_generation_size_ otherwise. 5410 if (!configured_) { 5411 if (!ConfigureHeapDefault()) return false; 5412 } 5413 5414 base::CallOnce(&initialize_gc_once, &InitializeGCOnce); 5415 5416 // Set up memory allocator. 5417 memory_allocator_ = new MemoryAllocator(isolate_); 5418 if (!memory_allocator_->SetUp(MaxReserved(), MaxExecutableSize(), 5419 code_range_size_)) 5420 return false; 5421 5422 // Initialize store buffer. 5423 store_buffer_ = new StoreBuffer(this); 5424 5425 // Initialize incremental marking. 5426 incremental_marking_ = new IncrementalMarking(this); 5427 5428 for (int i = 0; i <= LAST_SPACE; i++) { 5429 space_[i] = nullptr; 5430 } 5431 5432 space_[NEW_SPACE] = new_space_ = new NewSpace(this); 5433 if (!new_space_->SetUp(initial_semispace_size_, max_semi_space_size_)) { 5434 return false; 5435 } 5436 new_space_top_after_last_gc_ = new_space()->top(); 5437 5438 space_[OLD_SPACE] = old_space_ = 5439 new OldSpace(this, OLD_SPACE, NOT_EXECUTABLE); 5440 if (!old_space_->SetUp()) return false; 5441 5442 space_[CODE_SPACE] = code_space_ = new OldSpace(this, CODE_SPACE, EXECUTABLE); 5443 if (!code_space_->SetUp()) return false; 5444 5445 space_[MAP_SPACE] = map_space_ = new MapSpace(this, MAP_SPACE); 5446 if (!map_space_->SetUp()) return false; 5447 5448 // The large object code space may contain code or data. We set the memory 5449 // to be non-executable here for safety, but this means we need to enable it 5450 // explicitly when allocating large code objects. 5451 space_[LO_SPACE] = lo_space_ = new LargeObjectSpace(this, LO_SPACE); 5452 if (!lo_space_->SetUp()) return false; 5453 5454 // Set up the seed that is used to randomize the string hash function. 5455 DCHECK(hash_seed() == 0); 5456 if (FLAG_randomize_hashes) { 5457 if (FLAG_hash_seed == 0) { 5458 int rnd = isolate()->random_number_generator()->NextInt(); 5459 set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask)); 5460 } else { 5461 set_hash_seed(Smi::FromInt(FLAG_hash_seed)); 5462 } 5463 } 5464 5465 for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount); 5466 i++) { 5467 deferred_counters_[i] = 0; 5468 } 5469 5470 tracer_ = new GCTracer(this); 5471 scavenge_collector_ = new Scavenger(this); 5472 mark_compact_collector_ = new MarkCompactCollector(this); 5473 gc_idle_time_handler_ = new GCIdleTimeHandler(); 5474 memory_reducer_ = new MemoryReducer(this); 5475 if (V8_UNLIKELY(FLAG_gc_stats)) { 5476 live_object_stats_ = new ObjectStats(this); 5477 dead_object_stats_ = new ObjectStats(this); 5478 } 5479 scavenge_job_ = new ScavengeJob(); 5480 5481 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity())); 5482 LOG(isolate_, IntPtrTEvent("heap-available", Available())); 5483 5484 store_buffer()->SetUp(); 5485 5486 mark_compact_collector()->SetUp(); 5487 5488 idle_scavenge_observer_ = new IdleScavengeObserver( 5489 *this, ScavengeJob::kBytesAllocatedBeforeNextIdleTask); 5490 new_space()->AddAllocationObserver(idle_scavenge_observer_); 5491 5492 return true; 5493 } 5494 5495 5496 bool Heap::CreateHeapObjects() { 5497 // Create initial maps. 5498 if (!CreateInitialMaps()) return false; 5499 CreateApiObjects(); 5500 5501 // Create initial objects 5502 CreateInitialObjects(); 5503 CHECK_EQ(0u, gc_count_); 5504 5505 set_native_contexts_list(undefined_value()); 5506 set_allocation_sites_list(undefined_value()); 5507 5508 return true; 5509 } 5510 5511 5512 void Heap::SetStackLimits() { 5513 DCHECK(isolate_ != NULL); 5514 DCHECK(isolate_ == isolate()); 5515 // On 64 bit machines, pointers are generally out of range of Smis. We write 5516 // something that looks like an out of range Smi to the GC. 5517 5518 // Set up the special root array entries containing the stack limits. 5519 // These are actually addresses, but the tag makes the GC ignore it. 5520 roots_[kStackLimitRootIndex] = reinterpret_cast<Object*>( 5521 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag); 5522 roots_[kRealStackLimitRootIndex] = reinterpret_cast<Object*>( 5523 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag); 5524 } 5525 5526 void Heap::ClearStackLimits() { 5527 roots_[kStackLimitRootIndex] = Smi::kZero; 5528 roots_[kRealStackLimitRootIndex] = Smi::kZero; 5529 } 5530 5531 void Heap::PrintAlloctionsHash() { 5532 uint32_t hash = StringHasher::GetHashCore(raw_allocations_hash_); 5533 PrintF("\n### Allocations = %u, hash = 0x%08x\n", allocations_count(), hash); 5534 } 5535 5536 5537 void Heap::NotifyDeserializationComplete() { 5538 DCHECK_EQ(0, gc_count()); 5539 PagedSpaces spaces(this); 5540 for (PagedSpace* s = spaces.next(); s != NULL; s = spaces.next()) { 5541 if (isolate()->snapshot_available()) s->ShrinkImmortalImmovablePages(); 5542 #ifdef DEBUG 5543 // All pages right after bootstrapping must be marked as never-evacuate. 5544 for (Page* p : *s) { 5545 CHECK(p->NeverEvacuate()); 5546 } 5547 #endif // DEBUG 5548 } 5549 5550 deserialization_complete_ = true; 5551 } 5552 5553 void Heap::SetEmbedderHeapTracer(EmbedderHeapTracer* tracer) { 5554 DCHECK_EQ(gc_state_, HeapState::NOT_IN_GC); 5555 embedder_heap_tracer_ = tracer; 5556 } 5557 5558 void Heap::RegisterWrappersWithEmbedderHeapTracer() { 5559 DCHECK(UsingEmbedderHeapTracer()); 5560 if (wrappers_to_trace_.empty()) { 5561 return; 5562 } 5563 embedder_heap_tracer()->RegisterV8References(wrappers_to_trace_); 5564 wrappers_to_trace_.clear(); 5565 } 5566 5567 void Heap::TracePossibleWrapper(JSObject* js_object) { 5568 DCHECK(js_object->WasConstructedFromApiFunction()); 5569 if (js_object->GetInternalFieldCount() >= 2 && 5570 js_object->GetInternalField(0) && 5571 js_object->GetInternalField(0) != undefined_value() && 5572 js_object->GetInternalField(1) != undefined_value()) { 5573 DCHECK(reinterpret_cast<intptr_t>(js_object->GetInternalField(0)) % 2 == 0); 5574 wrappers_to_trace_.push_back(std::pair<void*, void*>( 5575 reinterpret_cast<void*>(js_object->GetInternalField(0)), 5576 reinterpret_cast<void*>(js_object->GetInternalField(1)))); 5577 } 5578 } 5579 5580 bool Heap::RequiresImmediateWrapperProcessing() { 5581 const size_t kTooManyWrappers = 16000; 5582 return wrappers_to_trace_.size() > kTooManyWrappers; 5583 } 5584 5585 void Heap::RegisterExternallyReferencedObject(Object** object) { 5586 HeapObject* heap_object = HeapObject::cast(*object); 5587 DCHECK(Contains(heap_object)); 5588 if (FLAG_incremental_marking_wrappers && incremental_marking()->IsMarking()) { 5589 IncrementalMarking::MarkGrey(this, heap_object); 5590 } else { 5591 DCHECK(mark_compact_collector()->in_use()); 5592 MarkBit mark_bit = ObjectMarking::MarkBitFrom(heap_object); 5593 mark_compact_collector()->MarkObject(heap_object, mark_bit); 5594 } 5595 } 5596 5597 void Heap::TearDown() { 5598 #ifdef VERIFY_HEAP 5599 if (FLAG_verify_heap) { 5600 Verify(); 5601 } 5602 #endif 5603 5604 UpdateMaximumCommitted(); 5605 5606 if (FLAG_print_max_heap_committed) { 5607 PrintF("\n"); 5608 PrintF("maximum_committed_by_heap=%" PRIuS " ", MaximumCommittedMemory()); 5609 PrintF("maximum_committed_by_new_space=%" PRIuS " ", 5610 new_space_->MaximumCommittedMemory()); 5611 PrintF("maximum_committed_by_old_space=%" PRIuS " ", 5612 old_space_->MaximumCommittedMemory()); 5613 PrintF("maximum_committed_by_code_space=%" PRIuS " ", 5614 code_space_->MaximumCommittedMemory()); 5615 PrintF("maximum_committed_by_map_space=%" PRIuS " ", 5616 map_space_->MaximumCommittedMemory()); 5617 PrintF("maximum_committed_by_lo_space=%" PRIuS " ", 5618 lo_space_->MaximumCommittedMemory()); 5619 PrintF("\n\n"); 5620 } 5621 5622 if (FLAG_verify_predictable) { 5623 PrintAlloctionsHash(); 5624 } 5625 5626 new_space()->RemoveAllocationObserver(idle_scavenge_observer_); 5627 delete idle_scavenge_observer_; 5628 idle_scavenge_observer_ = nullptr; 5629 5630 delete scavenge_collector_; 5631 scavenge_collector_ = nullptr; 5632 5633 if (mark_compact_collector_ != nullptr) { 5634 mark_compact_collector_->TearDown(); 5635 delete mark_compact_collector_; 5636 mark_compact_collector_ = nullptr; 5637 } 5638 5639 delete incremental_marking_; 5640 incremental_marking_ = nullptr; 5641 5642 delete gc_idle_time_handler_; 5643 gc_idle_time_handler_ = nullptr; 5644 5645 if (memory_reducer_ != nullptr) { 5646 memory_reducer_->TearDown(); 5647 delete memory_reducer_; 5648 memory_reducer_ = nullptr; 5649 } 5650 5651 if (live_object_stats_ != nullptr) { 5652 delete live_object_stats_; 5653 live_object_stats_ = nullptr; 5654 } 5655 5656 if (dead_object_stats_ != nullptr) { 5657 delete dead_object_stats_; 5658 dead_object_stats_ = nullptr; 5659 } 5660 5661 delete scavenge_job_; 5662 scavenge_job_ = nullptr; 5663 5664 isolate_->global_handles()->TearDown(); 5665 5666 external_string_table_.TearDown(); 5667 5668 delete tracer_; 5669 tracer_ = nullptr; 5670 5671 new_space_->TearDown(); 5672 delete new_space_; 5673 new_space_ = nullptr; 5674 5675 if (old_space_ != NULL) { 5676 delete old_space_; 5677 old_space_ = NULL; 5678 } 5679 5680 if (code_space_ != NULL) { 5681 delete code_space_; 5682 code_space_ = NULL; 5683 } 5684 5685 if (map_space_ != NULL) { 5686 delete map_space_; 5687 map_space_ = NULL; 5688 } 5689 5690 if (lo_space_ != NULL) { 5691 lo_space_->TearDown(); 5692 delete lo_space_; 5693 lo_space_ = NULL; 5694 } 5695 5696 store_buffer()->TearDown(); 5697 5698 memory_allocator()->TearDown(); 5699 5700 StrongRootsList* next = NULL; 5701 for (StrongRootsList* list = strong_roots_list_; list; list = next) { 5702 next = list->next; 5703 delete list; 5704 } 5705 strong_roots_list_ = NULL; 5706 5707 delete store_buffer_; 5708 store_buffer_ = nullptr; 5709 5710 delete memory_allocator_; 5711 memory_allocator_ = nullptr; 5712 } 5713 5714 5715 void Heap::AddGCPrologueCallback(v8::Isolate::GCCallback callback, 5716 GCType gc_type, bool pass_isolate) { 5717 DCHECK(callback != NULL); 5718 GCCallbackPair pair(callback, gc_type, pass_isolate); 5719 DCHECK(!gc_prologue_callbacks_.Contains(pair)); 5720 return gc_prologue_callbacks_.Add(pair); 5721 } 5722 5723 5724 void Heap::RemoveGCPrologueCallback(v8::Isolate::GCCallback callback) { 5725 DCHECK(callback != NULL); 5726 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { 5727 if (gc_prologue_callbacks_[i].callback == callback) { 5728 gc_prologue_callbacks_.Remove(i); 5729 return; 5730 } 5731 } 5732 UNREACHABLE(); 5733 } 5734 5735 5736 void Heap::AddGCEpilogueCallback(v8::Isolate::GCCallback callback, 5737 GCType gc_type, bool pass_isolate) { 5738 DCHECK(callback != NULL); 5739 GCCallbackPair pair(callback, gc_type, pass_isolate); 5740 DCHECK(!gc_epilogue_callbacks_.Contains(pair)); 5741 return gc_epilogue_callbacks_.Add(pair); 5742 } 5743 5744 5745 void Heap::RemoveGCEpilogueCallback(v8::Isolate::GCCallback callback) { 5746 DCHECK(callback != NULL); 5747 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) { 5748 if (gc_epilogue_callbacks_[i].callback == callback) { 5749 gc_epilogue_callbacks_.Remove(i); 5750 return; 5751 } 5752 } 5753 UNREACHABLE(); 5754 } 5755 5756 // TODO(ishell): Find a better place for this. 5757 void Heap::AddWeakNewSpaceObjectToCodeDependency(Handle<HeapObject> obj, 5758 Handle<WeakCell> code) { 5759 DCHECK(InNewSpace(*obj)); 5760 DCHECK(!InNewSpace(*code)); 5761 Handle<ArrayList> list(weak_new_space_object_to_code_list(), isolate()); 5762 list = ArrayList::Add(list, isolate()->factory()->NewWeakCell(obj), code); 5763 if (*list != weak_new_space_object_to_code_list()) { 5764 set_weak_new_space_object_to_code_list(*list); 5765 } 5766 } 5767 5768 // TODO(ishell): Find a better place for this. 5769 void Heap::AddWeakObjectToCodeDependency(Handle<HeapObject> obj, 5770 Handle<DependentCode> dep) { 5771 DCHECK(!InNewSpace(*obj)); 5772 DCHECK(!InNewSpace(*dep)); 5773 Handle<WeakHashTable> table(weak_object_to_code_table(), isolate()); 5774 table = WeakHashTable::Put(table, obj, dep); 5775 if (*table != weak_object_to_code_table()) 5776 set_weak_object_to_code_table(*table); 5777 DCHECK_EQ(*dep, LookupWeakObjectToCodeDependency(obj)); 5778 } 5779 5780 5781 DependentCode* Heap::LookupWeakObjectToCodeDependency(Handle<HeapObject> obj) { 5782 Object* dep = weak_object_to_code_table()->Lookup(obj); 5783 if (dep->IsDependentCode()) return DependentCode::cast(dep); 5784 return DependentCode::cast(empty_fixed_array()); 5785 } 5786 5787 namespace { 5788 void CompactWeakFixedArray(Object* object) { 5789 if (object->IsWeakFixedArray()) { 5790 WeakFixedArray* array = WeakFixedArray::cast(object); 5791 array->Compact<WeakFixedArray::NullCallback>(); 5792 } 5793 } 5794 } // anonymous namespace 5795 5796 void Heap::CompactWeakFixedArrays() { 5797 // Find known WeakFixedArrays and compact them. 5798 HeapIterator iterator(this); 5799 for (HeapObject* o = iterator.next(); o != NULL; o = iterator.next()) { 5800 if (o->IsPrototypeInfo()) { 5801 Object* prototype_users = PrototypeInfo::cast(o)->prototype_users(); 5802 if (prototype_users->IsWeakFixedArray()) { 5803 WeakFixedArray* array = WeakFixedArray::cast(prototype_users); 5804 array->Compact<JSObject::PrototypeRegistryCompactionCallback>(); 5805 } 5806 } else if (o->IsScript()) { 5807 CompactWeakFixedArray(Script::cast(o)->shared_function_infos()); 5808 } 5809 } 5810 CompactWeakFixedArray(noscript_shared_function_infos()); 5811 CompactWeakFixedArray(script_list()); 5812 CompactWeakFixedArray(weak_stack_trace_list()); 5813 } 5814 5815 void Heap::AddRetainedMap(Handle<Map> map) { 5816 Handle<WeakCell> cell = Map::WeakCellForMap(map); 5817 Handle<ArrayList> array(retained_maps(), isolate()); 5818 if (array->IsFull()) { 5819 CompactRetainedMaps(*array); 5820 } 5821 array = ArrayList::Add( 5822 array, cell, handle(Smi::FromInt(FLAG_retain_maps_for_n_gc), isolate()), 5823 ArrayList::kReloadLengthAfterAllocation); 5824 if (*array != retained_maps()) { 5825 set_retained_maps(*array); 5826 } 5827 } 5828 5829 5830 void Heap::CompactRetainedMaps(ArrayList* retained_maps) { 5831 DCHECK_EQ(retained_maps, this->retained_maps()); 5832 int length = retained_maps->Length(); 5833 int new_length = 0; 5834 int new_number_of_disposed_maps = 0; 5835 // This loop compacts the array by removing cleared weak cells. 5836 for (int i = 0; i < length; i += 2) { 5837 DCHECK(retained_maps->Get(i)->IsWeakCell()); 5838 WeakCell* cell = WeakCell::cast(retained_maps->Get(i)); 5839 Object* age = retained_maps->Get(i + 1); 5840 if (cell->cleared()) continue; 5841 if (i != new_length) { 5842 retained_maps->Set(new_length, cell); 5843 retained_maps->Set(new_length + 1, age); 5844 } 5845 if (i < number_of_disposed_maps_) { 5846 new_number_of_disposed_maps += 2; 5847 } 5848 new_length += 2; 5849 } 5850 number_of_disposed_maps_ = new_number_of_disposed_maps; 5851 Object* undefined = undefined_value(); 5852 for (int i = new_length; i < length; i++) { 5853 retained_maps->Clear(i, undefined); 5854 } 5855 if (new_length != length) retained_maps->SetLength(new_length); 5856 } 5857 5858 void Heap::FatalProcessOutOfMemory(const char* location, bool is_heap_oom) { 5859 v8::internal::V8::FatalProcessOutOfMemory(location, is_heap_oom); 5860 } 5861 5862 #ifdef DEBUG 5863 5864 class PrintHandleVisitor : public ObjectVisitor { 5865 public: 5866 void VisitPointers(Object** start, Object** end) override { 5867 for (Object** p = start; p < end; p++) 5868 PrintF(" handle %p to %p\n", reinterpret_cast<void*>(p), 5869 reinterpret_cast<void*>(*p)); 5870 } 5871 }; 5872 5873 5874 void Heap::PrintHandles() { 5875 PrintF("Handles:\n"); 5876 PrintHandleVisitor v; 5877 isolate_->handle_scope_implementer()->Iterate(&v); 5878 } 5879 5880 #endif 5881 5882 class CheckHandleCountVisitor : public ObjectVisitor { 5883 public: 5884 CheckHandleCountVisitor() : handle_count_(0) {} 5885 ~CheckHandleCountVisitor() override { 5886 CHECK(handle_count_ < HandleScope::kCheckHandleThreshold); 5887 } 5888 void VisitPointers(Object** start, Object** end) override { 5889 handle_count_ += end - start; 5890 } 5891 5892 private: 5893 ptrdiff_t handle_count_; 5894 }; 5895 5896 5897 void Heap::CheckHandleCount() { 5898 CheckHandleCountVisitor v; 5899 isolate_->handle_scope_implementer()->Iterate(&v); 5900 } 5901 5902 void Heap::ClearRecordedSlot(HeapObject* object, Object** slot) { 5903 if (!InNewSpace(object)) { 5904 Address slot_addr = reinterpret_cast<Address>(slot); 5905 Page* page = Page::FromAddress(slot_addr); 5906 DCHECK_EQ(page->owner()->identity(), OLD_SPACE); 5907 store_buffer()->DeleteEntry(slot_addr); 5908 RememberedSet<OLD_TO_OLD>::Remove(page, slot_addr); 5909 } 5910 } 5911 5912 void Heap::ClearRecordedSlotRange(Address start, Address end) { 5913 Page* page = Page::FromAddress(start); 5914 if (!page->InNewSpace()) { 5915 DCHECK_EQ(page->owner()->identity(), OLD_SPACE); 5916 store_buffer()->DeleteEntry(start, end); 5917 RememberedSet<OLD_TO_OLD>::RemoveRange(page, start, end, 5918 SlotSet::FREE_EMPTY_BUCKETS); 5919 } 5920 } 5921 5922 void Heap::RecordWriteIntoCodeSlow(Code* host, RelocInfo* rinfo, 5923 Object* value) { 5924 DCHECK(InNewSpace(value)); 5925 Page* source_page = Page::FromAddress(reinterpret_cast<Address>(host)); 5926 RelocInfo::Mode rmode = rinfo->rmode(); 5927 Address addr = rinfo->pc(); 5928 SlotType slot_type = SlotTypeForRelocInfoMode(rmode); 5929 if (rinfo->IsInConstantPool()) { 5930 addr = rinfo->constant_pool_entry_address(); 5931 if (RelocInfo::IsCodeTarget(rmode)) { 5932 slot_type = CODE_ENTRY_SLOT; 5933 } else { 5934 DCHECK(RelocInfo::IsEmbeddedObject(rmode)); 5935 slot_type = OBJECT_SLOT; 5936 } 5937 } 5938 RememberedSet<OLD_TO_NEW>::InsertTyped( 5939 source_page, reinterpret_cast<Address>(host), slot_type, addr); 5940 } 5941 5942 void Heap::RecordWritesIntoCode(Code* code) { 5943 for (RelocIterator it(code, RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT)); 5944 !it.done(); it.next()) { 5945 RecordWriteIntoCode(code, it.rinfo(), it.rinfo()->target_object()); 5946 } 5947 } 5948 5949 Space* AllSpaces::next() { 5950 switch (counter_++) { 5951 case NEW_SPACE: 5952 return heap_->new_space(); 5953 case OLD_SPACE: 5954 return heap_->old_space(); 5955 case CODE_SPACE: 5956 return heap_->code_space(); 5957 case MAP_SPACE: 5958 return heap_->map_space(); 5959 case LO_SPACE: 5960 return heap_->lo_space(); 5961 default: 5962 return NULL; 5963 } 5964 } 5965 5966 PagedSpace* PagedSpaces::next() { 5967 switch (counter_++) { 5968 case OLD_SPACE: 5969 return heap_->old_space(); 5970 case CODE_SPACE: 5971 return heap_->code_space(); 5972 case MAP_SPACE: 5973 return heap_->map_space(); 5974 default: 5975 return NULL; 5976 } 5977 } 5978 5979 5980 OldSpace* OldSpaces::next() { 5981 switch (counter_++) { 5982 case OLD_SPACE: 5983 return heap_->old_space(); 5984 case CODE_SPACE: 5985 return heap_->code_space(); 5986 default: 5987 return NULL; 5988 } 5989 } 5990 5991 SpaceIterator::SpaceIterator(Heap* heap) 5992 : heap_(heap), current_space_(FIRST_SPACE - 1) {} 5993 5994 SpaceIterator::~SpaceIterator() { 5995 } 5996 5997 5998 bool SpaceIterator::has_next() { 5999 // Iterate until no more spaces. 6000 return current_space_ != LAST_SPACE; 6001 } 6002 6003 Space* SpaceIterator::next() { 6004 DCHECK(has_next()); 6005 return heap_->space(++current_space_); 6006 } 6007 6008 6009 class HeapObjectsFilter { 6010 public: 6011 virtual ~HeapObjectsFilter() {} 6012 virtual bool SkipObject(HeapObject* object) = 0; 6013 }; 6014 6015 6016 class UnreachableObjectsFilter : public HeapObjectsFilter { 6017 public: 6018 explicit UnreachableObjectsFilter(Heap* heap) : heap_(heap) { 6019 MarkReachableObjects(); 6020 } 6021 6022 ~UnreachableObjectsFilter() { 6023 heap_->mark_compact_collector()->ClearMarkbits(); 6024 } 6025 6026 bool SkipObject(HeapObject* object) { 6027 if (object->IsFiller()) return true; 6028 MarkBit mark_bit = ObjectMarking::MarkBitFrom(object); 6029 return Marking::IsWhite(mark_bit); 6030 } 6031 6032 private: 6033 class MarkingVisitor : public ObjectVisitor { 6034 public: 6035 MarkingVisitor() : marking_stack_(10) {} 6036 6037 void VisitPointers(Object** start, Object** end) override { 6038 for (Object** p = start; p < end; p++) { 6039 if (!(*p)->IsHeapObject()) continue; 6040 HeapObject* obj = HeapObject::cast(*p); 6041 MarkBit mark_bit = ObjectMarking::MarkBitFrom(obj); 6042 if (Marking::IsWhite(mark_bit)) { 6043 Marking::WhiteToBlack(mark_bit); 6044 marking_stack_.Add(obj); 6045 } 6046 } 6047 } 6048 6049 void TransitiveClosure() { 6050 while (!marking_stack_.is_empty()) { 6051 HeapObject* obj = marking_stack_.RemoveLast(); 6052 obj->Iterate(this); 6053 } 6054 } 6055 6056 private: 6057 List<HeapObject*> marking_stack_; 6058 }; 6059 6060 void MarkReachableObjects() { 6061 MarkingVisitor visitor; 6062 heap_->IterateRoots(&visitor, VISIT_ALL); 6063 visitor.TransitiveClosure(); 6064 } 6065 6066 Heap* heap_; 6067 DisallowHeapAllocation no_allocation_; 6068 }; 6069 6070 6071 HeapIterator::HeapIterator(Heap* heap, 6072 HeapIterator::HeapObjectsFiltering filtering) 6073 : make_heap_iterable_helper_(heap), 6074 no_heap_allocation_(), 6075 heap_(heap), 6076 filtering_(filtering), 6077 filter_(nullptr), 6078 space_iterator_(nullptr), 6079 object_iterator_(nullptr) { 6080 heap_->heap_iterator_start(); 6081 // Start the iteration. 6082 space_iterator_ = new SpaceIterator(heap_); 6083 switch (filtering_) { 6084 case kFilterUnreachable: 6085 filter_ = new UnreachableObjectsFilter(heap_); 6086 break; 6087 default: 6088 break; 6089 } 6090 object_iterator_ = space_iterator_->next()->GetObjectIterator(); 6091 } 6092 6093 6094 HeapIterator::~HeapIterator() { 6095 heap_->heap_iterator_end(); 6096 #ifdef DEBUG 6097 // Assert that in filtering mode we have iterated through all 6098 // objects. Otherwise, heap will be left in an inconsistent state. 6099 if (filtering_ != kNoFiltering) { 6100 DCHECK(object_iterator_ == nullptr); 6101 } 6102 #endif 6103 delete space_iterator_; 6104 delete filter_; 6105 } 6106 6107 6108 HeapObject* HeapIterator::next() { 6109 if (filter_ == nullptr) return NextObject(); 6110 6111 HeapObject* obj = NextObject(); 6112 while ((obj != nullptr) && (filter_->SkipObject(obj))) obj = NextObject(); 6113 return obj; 6114 } 6115 6116 6117 HeapObject* HeapIterator::NextObject() { 6118 // No iterator means we are done. 6119 if (object_iterator_.get() == nullptr) return nullptr; 6120 6121 if (HeapObject* obj = object_iterator_.get()->Next()) { 6122 // If the current iterator has more objects we are fine. 6123 return obj; 6124 } else { 6125 // Go though the spaces looking for one that has objects. 6126 while (space_iterator_->has_next()) { 6127 object_iterator_ = space_iterator_->next()->GetObjectIterator(); 6128 if (HeapObject* obj = object_iterator_.get()->Next()) { 6129 return obj; 6130 } 6131 } 6132 } 6133 // Done with the last space. 6134 object_iterator_.reset(nullptr); 6135 return nullptr; 6136 } 6137 6138 6139 #ifdef DEBUG 6140 6141 Object* const PathTracer::kAnyGlobalObject = NULL; 6142 6143 class PathTracer::MarkVisitor : public ObjectVisitor { 6144 public: 6145 explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {} 6146 6147 void VisitPointers(Object** start, Object** end) override { 6148 // Scan all HeapObject pointers in [start, end) 6149 for (Object** p = start; !tracer_->found() && (p < end); p++) { 6150 if ((*p)->IsHeapObject()) tracer_->MarkRecursively(p, this); 6151 } 6152 } 6153 6154 private: 6155 PathTracer* tracer_; 6156 }; 6157 6158 6159 class PathTracer::UnmarkVisitor : public ObjectVisitor { 6160 public: 6161 explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {} 6162 6163 void VisitPointers(Object** start, Object** end) override { 6164 // Scan all HeapObject pointers in [start, end) 6165 for (Object** p = start; p < end; p++) { 6166 if ((*p)->IsHeapObject()) tracer_->UnmarkRecursively(p, this); 6167 } 6168 } 6169 6170 private: 6171 PathTracer* tracer_; 6172 }; 6173 6174 6175 void PathTracer::VisitPointers(Object** start, Object** end) { 6176 bool done = ((what_to_find_ == FIND_FIRST) && found_target_); 6177 // Visit all HeapObject pointers in [start, end) 6178 for (Object** p = start; !done && (p < end); p++) { 6179 if ((*p)->IsHeapObject()) { 6180 TracePathFrom(p); 6181 done = ((what_to_find_ == FIND_FIRST) && found_target_); 6182 } 6183 } 6184 } 6185 6186 6187 void PathTracer::Reset() { 6188 found_target_ = false; 6189 object_stack_.Clear(); 6190 } 6191 6192 6193 void PathTracer::TracePathFrom(Object** root) { 6194 DCHECK((search_target_ == kAnyGlobalObject) || 6195 search_target_->IsHeapObject()); 6196 found_target_in_trace_ = false; 6197 Reset(); 6198 6199 MarkVisitor mark_visitor(this); 6200 MarkRecursively(root, &mark_visitor); 6201 6202 UnmarkVisitor unmark_visitor(this); 6203 UnmarkRecursively(root, &unmark_visitor); 6204 6205 ProcessResults(); 6206 } 6207 6208 6209 static bool SafeIsNativeContext(HeapObject* obj) { 6210 return obj->map() == obj->GetHeap()->root(Heap::kNativeContextMapRootIndex); 6211 } 6212 6213 6214 void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) { 6215 if (!(*p)->IsHeapObject()) return; 6216 6217 HeapObject* obj = HeapObject::cast(*p); 6218 6219 MapWord map_word = obj->map_word(); 6220 if (!map_word.ToMap()->IsHeapObject()) return; // visited before 6221 6222 if (found_target_in_trace_) return; // stop if target found 6223 object_stack_.Add(obj); 6224 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) || 6225 (obj == search_target_)) { 6226 found_target_in_trace_ = true; 6227 found_target_ = true; 6228 return; 6229 } 6230 6231 bool is_native_context = SafeIsNativeContext(obj); 6232 6233 // not visited yet 6234 Map* map = Map::cast(map_word.ToMap()); 6235 6236 MapWord marked_map_word = 6237 MapWord::FromRawValue(obj->map_word().ToRawValue() + kMarkTag); 6238 obj->set_map_word(marked_map_word); 6239 6240 // Scan the object body. 6241 if (is_native_context && (visit_mode_ == VISIT_ONLY_STRONG)) { 6242 // This is specialized to scan Context's properly. 6243 Object** start = 6244 reinterpret_cast<Object**>(obj->address() + Context::kHeaderSize); 6245 Object** end = 6246 reinterpret_cast<Object**>(obj->address() + Context::kHeaderSize + 6247 Context::FIRST_WEAK_SLOT * kPointerSize); 6248 mark_visitor->VisitPointers(start, end); 6249 } else { 6250 obj->IterateBody(map->instance_type(), obj->SizeFromMap(map), mark_visitor); 6251 } 6252 6253 // Scan the map after the body because the body is a lot more interesting 6254 // when doing leak detection. 6255 MarkRecursively(reinterpret_cast<Object**>(&map), mark_visitor); 6256 6257 if (!found_target_in_trace_) { // don't pop if found the target 6258 object_stack_.RemoveLast(); 6259 } 6260 } 6261 6262 6263 void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) { 6264 if (!(*p)->IsHeapObject()) return; 6265 6266 HeapObject* obj = HeapObject::cast(*p); 6267 6268 MapWord map_word = obj->map_word(); 6269 if (map_word.ToMap()->IsHeapObject()) return; // unmarked already 6270 6271 MapWord unmarked_map_word = 6272 MapWord::FromRawValue(map_word.ToRawValue() - kMarkTag); 6273 obj->set_map_word(unmarked_map_word); 6274 6275 Map* map = Map::cast(unmarked_map_word.ToMap()); 6276 6277 UnmarkRecursively(reinterpret_cast<Object**>(&map), unmark_visitor); 6278 6279 obj->IterateBody(map->instance_type(), obj->SizeFromMap(map), unmark_visitor); 6280 } 6281 6282 6283 void PathTracer::ProcessResults() { 6284 if (found_target_) { 6285 OFStream os(stdout); 6286 os << "=====================================\n" 6287 << "==== Path to object ====\n" 6288 << "=====================================\n\n"; 6289 6290 DCHECK(!object_stack_.is_empty()); 6291 for (int i = 0; i < object_stack_.length(); i++) { 6292 if (i > 0) os << "\n |\n |\n V\n\n"; 6293 object_stack_[i]->Print(os); 6294 } 6295 os << "=====================================\n"; 6296 } 6297 } 6298 6299 6300 // Triggers a depth-first traversal of reachable objects from one 6301 // given root object and finds a path to a specific heap object and 6302 // prints it. 6303 void Heap::TracePathToObjectFrom(Object* target, Object* root) { 6304 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL); 6305 tracer.VisitPointer(&root); 6306 } 6307 6308 6309 // Triggers a depth-first traversal of reachable objects from roots 6310 // and finds a path to a specific heap object and prints it. 6311 void Heap::TracePathToObject(Object* target) { 6312 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL); 6313 IterateRoots(&tracer, VISIT_ONLY_STRONG); 6314 } 6315 6316 6317 // Triggers a depth-first traversal of reachable objects from roots 6318 // and finds a path to any global object and prints it. Useful for 6319 // determining the source for leaks of global objects. 6320 void Heap::TracePathToGlobal() { 6321 PathTracer tracer(PathTracer::kAnyGlobalObject, PathTracer::FIND_ALL, 6322 VISIT_ALL); 6323 IterateRoots(&tracer, VISIT_ONLY_STRONG); 6324 } 6325 #endif 6326 6327 void Heap::UpdateTotalGCTime(double duration) { 6328 if (FLAG_trace_gc_verbose) { 6329 total_gc_time_ms_ += duration; 6330 } 6331 } 6332 6333 void Heap::ExternalStringTable::CleanUp() { 6334 int last = 0; 6335 Isolate* isolate = heap_->isolate(); 6336 for (int i = 0; i < new_space_strings_.length(); ++i) { 6337 if (new_space_strings_[i]->IsTheHole(isolate)) { 6338 continue; 6339 } 6340 DCHECK(new_space_strings_[i]->IsExternalString()); 6341 if (heap_->InNewSpace(new_space_strings_[i])) { 6342 new_space_strings_[last++] = new_space_strings_[i]; 6343 } else { 6344 old_space_strings_.Add(new_space_strings_[i]); 6345 } 6346 } 6347 new_space_strings_.Rewind(last); 6348 new_space_strings_.Trim(); 6349 6350 last = 0; 6351 for (int i = 0; i < old_space_strings_.length(); ++i) { 6352 if (old_space_strings_[i]->IsTheHole(isolate)) { 6353 continue; 6354 } 6355 DCHECK(old_space_strings_[i]->IsExternalString()); 6356 DCHECK(!heap_->InNewSpace(old_space_strings_[i])); 6357 old_space_strings_[last++] = old_space_strings_[i]; 6358 } 6359 old_space_strings_.Rewind(last); 6360 old_space_strings_.Trim(); 6361 #ifdef VERIFY_HEAP 6362 if (FLAG_verify_heap) { 6363 Verify(); 6364 } 6365 #endif 6366 } 6367 6368 void Heap::ExternalStringTable::TearDown() { 6369 for (int i = 0; i < new_space_strings_.length(); ++i) { 6370 heap_->FinalizeExternalString(ExternalString::cast(new_space_strings_[i])); 6371 } 6372 new_space_strings_.Free(); 6373 for (int i = 0; i < old_space_strings_.length(); ++i) { 6374 heap_->FinalizeExternalString(ExternalString::cast(old_space_strings_[i])); 6375 } 6376 old_space_strings_.Free(); 6377 } 6378 6379 6380 void Heap::RememberUnmappedPage(Address page, bool compacted) { 6381 uintptr_t p = reinterpret_cast<uintptr_t>(page); 6382 // Tag the page pointer to make it findable in the dump file. 6383 if (compacted) { 6384 p ^= 0xc1ead & (Page::kPageSize - 1); // Cleared. 6385 } else { 6386 p ^= 0x1d1ed & (Page::kPageSize - 1); // I died. 6387 } 6388 remembered_unmapped_pages_[remembered_unmapped_pages_index_] = 6389 reinterpret_cast<Address>(p); 6390 remembered_unmapped_pages_index_++; 6391 remembered_unmapped_pages_index_ %= kRememberedUnmappedPages; 6392 } 6393 6394 6395 void Heap::RegisterStrongRoots(Object** start, Object** end) { 6396 StrongRootsList* list = new StrongRootsList(); 6397 list->next = strong_roots_list_; 6398 list->start = start; 6399 list->end = end; 6400 strong_roots_list_ = list; 6401 } 6402 6403 6404 void Heap::UnregisterStrongRoots(Object** start) { 6405 StrongRootsList* prev = NULL; 6406 StrongRootsList* list = strong_roots_list_; 6407 while (list != nullptr) { 6408 StrongRootsList* next = list->next; 6409 if (list->start == start) { 6410 if (prev) { 6411 prev->next = next; 6412 } else { 6413 strong_roots_list_ = next; 6414 } 6415 delete list; 6416 } else { 6417 prev = list; 6418 } 6419 list = next; 6420 } 6421 } 6422 6423 6424 size_t Heap::NumberOfTrackedHeapObjectTypes() { 6425 return ObjectStats::OBJECT_STATS_COUNT; 6426 } 6427 6428 6429 size_t Heap::ObjectCountAtLastGC(size_t index) { 6430 if (live_object_stats_ == nullptr || index >= ObjectStats::OBJECT_STATS_COUNT) 6431 return 0; 6432 return live_object_stats_->object_count_last_gc(index); 6433 } 6434 6435 6436 size_t Heap::ObjectSizeAtLastGC(size_t index) { 6437 if (live_object_stats_ == nullptr || index >= ObjectStats::OBJECT_STATS_COUNT) 6438 return 0; 6439 return live_object_stats_->object_size_last_gc(index); 6440 } 6441 6442 6443 bool Heap::GetObjectTypeName(size_t index, const char** object_type, 6444 const char** object_sub_type) { 6445 if (index >= ObjectStats::OBJECT_STATS_COUNT) return false; 6446 6447 switch (static_cast<int>(index)) { 6448 #define COMPARE_AND_RETURN_NAME(name) \ 6449 case name: \ 6450 *object_type = #name; \ 6451 *object_sub_type = ""; \ 6452 return true; 6453 INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME) 6454 #undef COMPARE_AND_RETURN_NAME 6455 #define COMPARE_AND_RETURN_NAME(name) \ 6456 case ObjectStats::FIRST_CODE_KIND_SUB_TYPE + Code::name: \ 6457 *object_type = "CODE_TYPE"; \ 6458 *object_sub_type = "CODE_KIND/" #name; \ 6459 return true; 6460 CODE_KIND_LIST(COMPARE_AND_RETURN_NAME) 6461 #undef COMPARE_AND_RETURN_NAME 6462 #define COMPARE_AND_RETURN_NAME(name) \ 6463 case ObjectStats::FIRST_FIXED_ARRAY_SUB_TYPE + name: \ 6464 *object_type = "FIXED_ARRAY_TYPE"; \ 6465 *object_sub_type = #name; \ 6466 return true; 6467 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME) 6468 #undef COMPARE_AND_RETURN_NAME 6469 #define COMPARE_AND_RETURN_NAME(name) \ 6470 case ObjectStats::FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - \ 6471 Code::kFirstCodeAge: \ 6472 *object_type = "CODE_TYPE"; \ 6473 *object_sub_type = "CODE_AGE/" #name; \ 6474 return true; 6475 CODE_AGE_LIST_COMPLETE(COMPARE_AND_RETURN_NAME) 6476 #undef COMPARE_AND_RETURN_NAME 6477 } 6478 return false; 6479 } 6480 6481 6482 // static 6483 int Heap::GetStaticVisitorIdForMap(Map* map) { 6484 return StaticVisitorBase::GetVisitorId(map); 6485 } 6486 6487 } // namespace internal 6488 } // namespace v8 6489