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