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