1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "accessors.h" 31 #include "api.h" 32 #include "bootstrapper.h" 33 #include "codegen.h" 34 #include "compilation-cache.h" 35 #include "cpu-profiler.h" 36 #include "debug.h" 37 #include "deoptimizer.h" 38 #include "global-handles.h" 39 #include "heap-profiler.h" 40 #include "incremental-marking.h" 41 #include "isolate-inl.h" 42 #include "mark-compact.h" 43 #include "natives.h" 44 #include "objects-visiting.h" 45 #include "objects-visiting-inl.h" 46 #include "once.h" 47 #include "runtime-profiler.h" 48 #include "scopeinfo.h" 49 #include "snapshot.h" 50 #include "store-buffer.h" 51 #include "utils/random-number-generator.h" 52 #include "v8threads.h" 53 #include "v8utils.h" 54 #include "vm-state-inl.h" 55 #if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP 56 #include "regexp-macro-assembler.h" 57 #include "arm/regexp-macro-assembler-arm.h" 58 #endif 59 #if V8_TARGET_ARCH_MIPS && !V8_INTERPRETED_REGEXP 60 #include "regexp-macro-assembler.h" 61 #include "mips/regexp-macro-assembler-mips.h" 62 #endif 63 64 namespace v8 { 65 namespace internal { 66 67 68 Heap::Heap() 69 : isolate_(NULL), 70 code_range_size_(kIs64BitArch ? 512 * MB : 0), 71 // semispace_size_ should be a power of 2 and old_generation_size_ should be 72 // a multiple of Page::kPageSize. 73 reserved_semispace_size_(8 * (kPointerSize / 4) * MB), 74 max_semispace_size_(8 * (kPointerSize / 4) * MB), 75 initial_semispace_size_(Page::kPageSize), 76 max_old_generation_size_(700ul * (kPointerSize / 4) * MB), 77 max_executable_size_(256ul * (kPointerSize / 4) * MB), 78 // Variables set based on semispace_size_ and old_generation_size_ in 79 // ConfigureHeap (survived_since_last_expansion_, external_allocation_limit_) 80 // Will be 4 * reserved_semispace_size_ to ensure that young 81 // generation can be aligned to its size. 82 maximum_committed_(0), 83 survived_since_last_expansion_(0), 84 sweep_generation_(0), 85 always_allocate_scope_depth_(0), 86 linear_allocation_scope_depth_(0), 87 contexts_disposed_(0), 88 global_ic_age_(0), 89 flush_monomorphic_ics_(false), 90 scan_on_scavenge_pages_(0), 91 new_space_(this), 92 old_pointer_space_(NULL), 93 old_data_space_(NULL), 94 code_space_(NULL), 95 map_space_(NULL), 96 cell_space_(NULL), 97 property_cell_space_(NULL), 98 lo_space_(NULL), 99 gc_state_(NOT_IN_GC), 100 gc_post_processing_depth_(0), 101 ms_count_(0), 102 gc_count_(0), 103 remembered_unmapped_pages_index_(0), 104 unflattened_strings_length_(0), 105 #ifdef DEBUG 106 allocation_timeout_(0), 107 disallow_allocation_failure_(false), 108 #endif // DEBUG 109 new_space_high_promotion_mode_active_(false), 110 old_generation_allocation_limit_(kMinimumOldGenerationAllocationLimit), 111 size_of_old_gen_at_last_old_space_gc_(0), 112 external_allocation_limit_(0), 113 amount_of_external_allocated_memory_(0), 114 amount_of_external_allocated_memory_at_last_global_gc_(0), 115 old_gen_exhausted_(false), 116 inline_allocation_disabled_(false), 117 store_buffer_rebuilder_(store_buffer()), 118 hidden_string_(NULL), 119 gc_safe_size_of_old_object_(NULL), 120 total_regexp_code_generated_(0), 121 tracer_(NULL), 122 young_survivors_after_last_gc_(0), 123 high_survival_rate_period_length_(0), 124 low_survival_rate_period_length_(0), 125 survival_rate_(0), 126 previous_survival_rate_trend_(Heap::STABLE), 127 survival_rate_trend_(Heap::STABLE), 128 max_gc_pause_(0.0), 129 total_gc_time_ms_(0.0), 130 max_alive_after_gc_(0), 131 min_in_mutator_(kMaxInt), 132 alive_after_last_gc_(0), 133 last_gc_end_timestamp_(0.0), 134 marking_time_(0.0), 135 sweeping_time_(0.0), 136 store_buffer_(this), 137 marking_(this), 138 incremental_marking_(this), 139 number_idle_notifications_(0), 140 last_idle_notification_gc_count_(0), 141 last_idle_notification_gc_count_init_(false), 142 mark_sweeps_since_idle_round_started_(0), 143 gc_count_at_last_idle_gc_(0), 144 scavenges_since_last_idle_round_(kIdleScavengeThreshold), 145 full_codegen_bytes_generated_(0), 146 crankshaft_codegen_bytes_generated_(0), 147 gcs_since_last_deopt_(0), 148 #ifdef VERIFY_HEAP 149 no_weak_object_verification_scope_depth_(0), 150 #endif 151 promotion_queue_(this), 152 configured_(false), 153 chunks_queued_for_free_(NULL), 154 relocation_mutex_(NULL) { 155 // Allow build-time customization of the max semispace size. Building 156 // V8 with snapshots and a non-default max semispace size is much 157 // easier if you can define it as part of the build environment. 158 #if defined(V8_MAX_SEMISPACE_SIZE) 159 max_semispace_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE; 160 #endif 161 162 // Ensure old_generation_size_ is a multiple of kPageSize. 163 ASSERT(MB >= Page::kPageSize); 164 165 intptr_t max_virtual = OS::MaxVirtualMemory(); 166 167 if (max_virtual > 0) { 168 if (code_range_size_ > 0) { 169 // Reserve no more than 1/8 of the memory for the code range. 170 code_range_size_ = Min(code_range_size_, max_virtual >> 3); 171 } 172 } 173 174 memset(roots_, 0, sizeof(roots_[0]) * kRootListLength); 175 native_contexts_list_ = NULL; 176 array_buffers_list_ = Smi::FromInt(0); 177 allocation_sites_list_ = Smi::FromInt(0); 178 mark_compact_collector_.heap_ = this; 179 external_string_table_.heap_ = this; 180 // Put a dummy entry in the remembered pages so we can find the list the 181 // minidump even if there are no real unmapped pages. 182 RememberUnmappedPage(NULL, false); 183 184 ClearObjectStats(true); 185 } 186 187 188 intptr_t Heap::Capacity() { 189 if (!HasBeenSetUp()) return 0; 190 191 return new_space_.Capacity() + 192 old_pointer_space_->Capacity() + 193 old_data_space_->Capacity() + 194 code_space_->Capacity() + 195 map_space_->Capacity() + 196 cell_space_->Capacity() + 197 property_cell_space_->Capacity(); 198 } 199 200 201 intptr_t Heap::CommittedMemory() { 202 if (!HasBeenSetUp()) return 0; 203 204 return new_space_.CommittedMemory() + 205 old_pointer_space_->CommittedMemory() + 206 old_data_space_->CommittedMemory() + 207 code_space_->CommittedMemory() + 208 map_space_->CommittedMemory() + 209 cell_space_->CommittedMemory() + 210 property_cell_space_->CommittedMemory() + 211 lo_space_->Size(); 212 } 213 214 215 size_t Heap::CommittedPhysicalMemory() { 216 if (!HasBeenSetUp()) return 0; 217 218 return new_space_.CommittedPhysicalMemory() + 219 old_pointer_space_->CommittedPhysicalMemory() + 220 old_data_space_->CommittedPhysicalMemory() + 221 code_space_->CommittedPhysicalMemory() + 222 map_space_->CommittedPhysicalMemory() + 223 cell_space_->CommittedPhysicalMemory() + 224 property_cell_space_->CommittedPhysicalMemory() + 225 lo_space_->CommittedPhysicalMemory(); 226 } 227 228 229 intptr_t Heap::CommittedMemoryExecutable() { 230 if (!HasBeenSetUp()) return 0; 231 232 return isolate()->memory_allocator()->SizeExecutable(); 233 } 234 235 236 void Heap::UpdateMaximumCommitted() { 237 if (!HasBeenSetUp()) return; 238 239 intptr_t current_committed_memory = CommittedMemory(); 240 if (current_committed_memory > maximum_committed_) { 241 maximum_committed_ = current_committed_memory; 242 } 243 } 244 245 246 intptr_t Heap::Available() { 247 if (!HasBeenSetUp()) return 0; 248 249 return new_space_.Available() + 250 old_pointer_space_->Available() + 251 old_data_space_->Available() + 252 code_space_->Available() + 253 map_space_->Available() + 254 cell_space_->Available() + 255 property_cell_space_->Available(); 256 } 257 258 259 bool Heap::HasBeenSetUp() { 260 return old_pointer_space_ != NULL && 261 old_data_space_ != NULL && 262 code_space_ != NULL && 263 map_space_ != NULL && 264 cell_space_ != NULL && 265 property_cell_space_ != NULL && 266 lo_space_ != NULL; 267 } 268 269 270 int Heap::GcSafeSizeOfOldObject(HeapObject* object) { 271 if (IntrusiveMarking::IsMarked(object)) { 272 return IntrusiveMarking::SizeOfMarkedObject(object); 273 } 274 return object->SizeFromMap(object->map()); 275 } 276 277 278 GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space, 279 const char** reason) { 280 // Is global GC requested? 281 if (space != NEW_SPACE) { 282 isolate_->counters()->gc_compactor_caused_by_request()->Increment(); 283 *reason = "GC in old space requested"; 284 return MARK_COMPACTOR; 285 } 286 287 if (FLAG_gc_global || (FLAG_stress_compaction && (gc_count_ & 1) != 0)) { 288 *reason = "GC in old space forced by flags"; 289 return MARK_COMPACTOR; 290 } 291 292 // Is enough data promoted to justify a global GC? 293 if (OldGenerationAllocationLimitReached()) { 294 isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment(); 295 *reason = "promotion limit reached"; 296 return MARK_COMPACTOR; 297 } 298 299 // Have allocation in OLD and LO failed? 300 if (old_gen_exhausted_) { 301 isolate_->counters()-> 302 gc_compactor_caused_by_oldspace_exhaustion()->Increment(); 303 *reason = "old generations exhausted"; 304 return MARK_COMPACTOR; 305 } 306 307 // Is there enough space left in OLD to guarantee that a scavenge can 308 // succeed? 309 // 310 // Note that MemoryAllocator->MaxAvailable() undercounts the memory available 311 // for object promotion. It counts only the bytes that the memory 312 // allocator has not yet allocated from the OS and assigned to any space, 313 // and does not count available bytes already in the old space or code 314 // space. Undercounting is safe---we may get an unrequested full GC when 315 // a scavenge would have succeeded. 316 if (isolate_->memory_allocator()->MaxAvailable() <= new_space_.Size()) { 317 isolate_->counters()-> 318 gc_compactor_caused_by_oldspace_exhaustion()->Increment(); 319 *reason = "scavenge might not succeed"; 320 return MARK_COMPACTOR; 321 } 322 323 // Default 324 *reason = NULL; 325 return SCAVENGER; 326 } 327 328 329 // TODO(1238405): Combine the infrastructure for --heap-stats and 330 // --log-gc to avoid the complicated preprocessor and flag testing. 331 void Heap::ReportStatisticsBeforeGC() { 332 // Heap::ReportHeapStatistics will also log NewSpace statistics when 333 // compiled --log-gc is set. The following logic is used to avoid 334 // double logging. 335 #ifdef DEBUG 336 if (FLAG_heap_stats || FLAG_log_gc) new_space_.CollectStatistics(); 337 if (FLAG_heap_stats) { 338 ReportHeapStatistics("Before GC"); 339 } else if (FLAG_log_gc) { 340 new_space_.ReportStatistics(); 341 } 342 if (FLAG_heap_stats || FLAG_log_gc) new_space_.ClearHistograms(); 343 #else 344 if (FLAG_log_gc) { 345 new_space_.CollectStatistics(); 346 new_space_.ReportStatistics(); 347 new_space_.ClearHistograms(); 348 } 349 #endif // DEBUG 350 } 351 352 353 void Heap::PrintShortHeapStatistics() { 354 if (!FLAG_trace_gc_verbose) return; 355 PrintPID("Memory allocator, used: %6" V8_PTR_PREFIX "d KB" 356 ", available: %6" V8_PTR_PREFIX "d KB\n", 357 isolate_->memory_allocator()->Size() / KB, 358 isolate_->memory_allocator()->Available() / KB); 359 PrintPID("New space, used: %6" V8_PTR_PREFIX "d KB" 360 ", available: %6" V8_PTR_PREFIX "d KB" 361 ", committed: %6" V8_PTR_PREFIX "d KB\n", 362 new_space_.Size() / KB, 363 new_space_.Available() / KB, 364 new_space_.CommittedMemory() / KB); 365 PrintPID("Old pointers, used: %6" V8_PTR_PREFIX "d KB" 366 ", available: %6" V8_PTR_PREFIX "d KB" 367 ", committed: %6" V8_PTR_PREFIX "d KB\n", 368 old_pointer_space_->SizeOfObjects() / KB, 369 old_pointer_space_->Available() / KB, 370 old_pointer_space_->CommittedMemory() / KB); 371 PrintPID("Old data space, used: %6" V8_PTR_PREFIX "d KB" 372 ", available: %6" V8_PTR_PREFIX "d KB" 373 ", committed: %6" V8_PTR_PREFIX "d KB\n", 374 old_data_space_->SizeOfObjects() / KB, 375 old_data_space_->Available() / KB, 376 old_data_space_->CommittedMemory() / KB); 377 PrintPID("Code space, used: %6" V8_PTR_PREFIX "d KB" 378 ", available: %6" V8_PTR_PREFIX "d KB" 379 ", committed: %6" V8_PTR_PREFIX "d KB\n", 380 code_space_->SizeOfObjects() / KB, 381 code_space_->Available() / KB, 382 code_space_->CommittedMemory() / KB); 383 PrintPID("Map space, used: %6" V8_PTR_PREFIX "d KB" 384 ", available: %6" V8_PTR_PREFIX "d KB" 385 ", committed: %6" V8_PTR_PREFIX "d KB\n", 386 map_space_->SizeOfObjects() / KB, 387 map_space_->Available() / KB, 388 map_space_->CommittedMemory() / KB); 389 PrintPID("Cell space, used: %6" V8_PTR_PREFIX "d KB" 390 ", available: %6" V8_PTR_PREFIX "d KB" 391 ", committed: %6" V8_PTR_PREFIX "d KB\n", 392 cell_space_->SizeOfObjects() / KB, 393 cell_space_->Available() / KB, 394 cell_space_->CommittedMemory() / KB); 395 PrintPID("PropertyCell space, used: %6" V8_PTR_PREFIX "d KB" 396 ", available: %6" V8_PTR_PREFIX "d KB" 397 ", committed: %6" V8_PTR_PREFIX "d KB\n", 398 property_cell_space_->SizeOfObjects() / KB, 399 property_cell_space_->Available() / KB, 400 property_cell_space_->CommittedMemory() / KB); 401 PrintPID("Large object space, used: %6" V8_PTR_PREFIX "d KB" 402 ", available: %6" V8_PTR_PREFIX "d KB" 403 ", committed: %6" V8_PTR_PREFIX "d KB\n", 404 lo_space_->SizeOfObjects() / KB, 405 lo_space_->Available() / KB, 406 lo_space_->CommittedMemory() / KB); 407 PrintPID("All spaces, used: %6" V8_PTR_PREFIX "d KB" 408 ", available: %6" V8_PTR_PREFIX "d KB" 409 ", committed: %6" V8_PTR_PREFIX "d KB\n", 410 this->SizeOfObjects() / KB, 411 this->Available() / KB, 412 this->CommittedMemory() / KB); 413 PrintPID("External memory reported: %6" V8_PTR_PREFIX "d KB\n", 414 static_cast<intptr_t>(amount_of_external_allocated_memory_ / KB)); 415 PrintPID("Total time spent in GC : %.1f ms\n", total_gc_time_ms_); 416 } 417 418 419 // TODO(1238405): Combine the infrastructure for --heap-stats and 420 // --log-gc to avoid the complicated preprocessor and flag testing. 421 void Heap::ReportStatisticsAfterGC() { 422 // Similar to the before GC, we use some complicated logic to ensure that 423 // NewSpace statistics are logged exactly once when --log-gc is turned on. 424 #if defined(DEBUG) 425 if (FLAG_heap_stats) { 426 new_space_.CollectStatistics(); 427 ReportHeapStatistics("After GC"); 428 } else if (FLAG_log_gc) { 429 new_space_.ReportStatistics(); 430 } 431 #else 432 if (FLAG_log_gc) new_space_.ReportStatistics(); 433 #endif // DEBUG 434 } 435 436 437 void Heap::GarbageCollectionPrologue() { 438 { AllowHeapAllocation for_the_first_part_of_prologue; 439 isolate_->transcendental_cache()->Clear(); 440 ClearJSFunctionResultCaches(); 441 gc_count_++; 442 unflattened_strings_length_ = 0; 443 444 if (FLAG_flush_code && FLAG_flush_code_incrementally) { 445 mark_compact_collector()->EnableCodeFlushing(true); 446 } 447 448 #ifdef VERIFY_HEAP 449 if (FLAG_verify_heap) { 450 Verify(); 451 } 452 #endif 453 } 454 455 UpdateMaximumCommitted(); 456 457 #ifdef DEBUG 458 ASSERT(!AllowHeapAllocation::IsAllowed() && gc_state_ == NOT_IN_GC); 459 460 if (FLAG_gc_verbose) Print(); 461 462 ReportStatisticsBeforeGC(); 463 #endif // DEBUG 464 465 store_buffer()->GCPrologue(); 466 467 if (isolate()->concurrent_osr_enabled()) { 468 isolate()->optimizing_compiler_thread()->AgeBufferedOsrJobs(); 469 } 470 } 471 472 473 intptr_t Heap::SizeOfObjects() { 474 intptr_t total = 0; 475 AllSpaces spaces(this); 476 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { 477 total += space->SizeOfObjects(); 478 } 479 return total; 480 } 481 482 483 void Heap::ClearAllICsByKind(Code::Kind kind) { 484 HeapObjectIterator it(code_space()); 485 486 for (Object* object = it.Next(); object != NULL; object = it.Next()) { 487 Code* code = Code::cast(object); 488 Code::Kind current_kind = code->kind(); 489 if (current_kind == Code::FUNCTION || 490 current_kind == Code::OPTIMIZED_FUNCTION) { 491 code->ClearInlineCaches(kind); 492 } 493 } 494 } 495 496 497 void Heap::RepairFreeListsAfterBoot() { 498 PagedSpaces spaces(this); 499 for (PagedSpace* space = spaces.next(); 500 space != NULL; 501 space = spaces.next()) { 502 space->RepairFreeListsAfterBoot(); 503 } 504 } 505 506 507 void Heap::GarbageCollectionEpilogue() { 508 if (FLAG_allocation_site_pretenuring) { 509 int tenure_decisions = 0; 510 int dont_tenure_decisions = 0; 511 int allocation_mementos_found = 0; 512 513 Object* cur = allocation_sites_list(); 514 while (cur->IsAllocationSite()) { 515 AllocationSite* casted = AllocationSite::cast(cur); 516 allocation_mementos_found += casted->memento_found_count()->value(); 517 if (casted->DigestPretenuringFeedback()) { 518 if (casted->GetPretenureMode() == TENURED) { 519 tenure_decisions++; 520 } else { 521 dont_tenure_decisions++; 522 } 523 } 524 cur = casted->weak_next(); 525 } 526 527 // TODO(mvstanton): Pretenure decisions are only made once for an allocation 528 // site. Find a sane way to decide about revisiting the decision later. 529 530 if (FLAG_trace_track_allocation_sites && 531 (allocation_mementos_found > 0 || 532 tenure_decisions > 0 || 533 dont_tenure_decisions > 0)) { 534 PrintF("GC: (#mementos, #tenure decisions, #donttenure decisions) " 535 "(%d, %d, %d)\n", 536 allocation_mementos_found, 537 tenure_decisions, 538 dont_tenure_decisions); 539 } 540 } 541 542 store_buffer()->GCEpilogue(); 543 544 // In release mode, we only zap the from space under heap verification. 545 if (Heap::ShouldZapGarbage()) { 546 ZapFromSpace(); 547 } 548 549 #ifdef VERIFY_HEAP 550 if (FLAG_verify_heap) { 551 Verify(); 552 } 553 #endif 554 555 AllowHeapAllocation for_the_rest_of_the_epilogue; 556 557 #ifdef DEBUG 558 if (FLAG_print_global_handles) isolate_->global_handles()->Print(); 559 if (FLAG_print_handles) PrintHandles(); 560 if (FLAG_gc_verbose) Print(); 561 if (FLAG_code_stats) ReportCodeStatistics("After GC"); 562 #endif 563 if (FLAG_deopt_every_n_garbage_collections > 0) { 564 if (++gcs_since_last_deopt_ == FLAG_deopt_every_n_garbage_collections) { 565 Deoptimizer::DeoptimizeAll(isolate()); 566 gcs_since_last_deopt_ = 0; 567 } 568 } 569 570 UpdateMaximumCommitted(); 571 572 isolate_->counters()->alive_after_last_gc()->Set( 573 static_cast<int>(SizeOfObjects())); 574 575 isolate_->counters()->string_table_capacity()->Set( 576 string_table()->Capacity()); 577 isolate_->counters()->number_of_symbols()->Set( 578 string_table()->NumberOfElements()); 579 580 if (full_codegen_bytes_generated_ + crankshaft_codegen_bytes_generated_ > 0) { 581 isolate_->counters()->codegen_fraction_crankshaft()->AddSample( 582 static_cast<int>((crankshaft_codegen_bytes_generated_ * 100.0) / 583 (crankshaft_codegen_bytes_generated_ 584 + full_codegen_bytes_generated_))); 585 } 586 587 if (CommittedMemory() > 0) { 588 isolate_->counters()->external_fragmentation_total()->AddSample( 589 static_cast<int>(100 - (SizeOfObjects() * 100.0) / CommittedMemory())); 590 591 isolate_->counters()->heap_fraction_new_space()-> 592 AddSample(static_cast<int>( 593 (new_space()->CommittedMemory() * 100.0) / CommittedMemory())); 594 isolate_->counters()->heap_fraction_old_pointer_space()->AddSample( 595 static_cast<int>( 596 (old_pointer_space()->CommittedMemory() * 100.0) / 597 CommittedMemory())); 598 isolate_->counters()->heap_fraction_old_data_space()->AddSample( 599 static_cast<int>( 600 (old_data_space()->CommittedMemory() * 100.0) / 601 CommittedMemory())); 602 isolate_->counters()->heap_fraction_code_space()-> 603 AddSample(static_cast<int>( 604 (code_space()->CommittedMemory() * 100.0) / CommittedMemory())); 605 isolate_->counters()->heap_fraction_map_space()->AddSample( 606 static_cast<int>( 607 (map_space()->CommittedMemory() * 100.0) / CommittedMemory())); 608 isolate_->counters()->heap_fraction_cell_space()->AddSample( 609 static_cast<int>( 610 (cell_space()->CommittedMemory() * 100.0) / CommittedMemory())); 611 isolate_->counters()->heap_fraction_property_cell_space()-> 612 AddSample(static_cast<int>( 613 (property_cell_space()->CommittedMemory() * 100.0) / 614 CommittedMemory())); 615 isolate_->counters()->heap_fraction_lo_space()-> 616 AddSample(static_cast<int>( 617 (lo_space()->CommittedMemory() * 100.0) / CommittedMemory())); 618 619 isolate_->counters()->heap_sample_total_committed()->AddSample( 620 static_cast<int>(CommittedMemory() / KB)); 621 isolate_->counters()->heap_sample_total_used()->AddSample( 622 static_cast<int>(SizeOfObjects() / KB)); 623 isolate_->counters()->heap_sample_map_space_committed()->AddSample( 624 static_cast<int>(map_space()->CommittedMemory() / KB)); 625 isolate_->counters()->heap_sample_cell_space_committed()->AddSample( 626 static_cast<int>(cell_space()->CommittedMemory() / KB)); 627 isolate_->counters()-> 628 heap_sample_property_cell_space_committed()-> 629 AddSample(static_cast<int>( 630 property_cell_space()->CommittedMemory() / KB)); 631 isolate_->counters()->heap_sample_code_space_committed()->AddSample( 632 static_cast<int>(code_space()->CommittedMemory() / KB)); 633 634 isolate_->counters()->heap_sample_maximum_committed()->AddSample( 635 static_cast<int>(MaximumCommittedMemory() / KB)); 636 } 637 638 #define UPDATE_COUNTERS_FOR_SPACE(space) \ 639 isolate_->counters()->space##_bytes_available()->Set( \ 640 static_cast<int>(space()->Available())); \ 641 isolate_->counters()->space##_bytes_committed()->Set( \ 642 static_cast<int>(space()->CommittedMemory())); \ 643 isolate_->counters()->space##_bytes_used()->Set( \ 644 static_cast<int>(space()->SizeOfObjects())); 645 #define UPDATE_FRAGMENTATION_FOR_SPACE(space) \ 646 if (space()->CommittedMemory() > 0) { \ 647 isolate_->counters()->external_fragmentation_##space()->AddSample( \ 648 static_cast<int>(100 - \ 649 (space()->SizeOfObjects() * 100.0) / space()->CommittedMemory())); \ 650 } 651 #define UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(space) \ 652 UPDATE_COUNTERS_FOR_SPACE(space) \ 653 UPDATE_FRAGMENTATION_FOR_SPACE(space) 654 655 UPDATE_COUNTERS_FOR_SPACE(new_space) 656 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_pointer_space) 657 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_data_space) 658 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(code_space) 659 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(map_space) 660 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(cell_space) 661 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(property_cell_space) 662 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(lo_space) 663 #undef UPDATE_COUNTERS_FOR_SPACE 664 #undef UPDATE_FRAGMENTATION_FOR_SPACE 665 #undef UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE 666 667 #if defined(DEBUG) 668 ReportStatisticsAfterGC(); 669 #endif // DEBUG 670 #ifdef ENABLE_DEBUGGER_SUPPORT 671 isolate_->debug()->AfterGarbageCollection(); 672 #endif // ENABLE_DEBUGGER_SUPPORT 673 } 674 675 676 void Heap::CollectAllGarbage(int flags, const char* gc_reason) { 677 // Since we are ignoring the return value, the exact choice of space does 678 // not matter, so long as we do not specify NEW_SPACE, which would not 679 // cause a full GC. 680 mark_compact_collector_.SetFlags(flags); 681 CollectGarbage(OLD_POINTER_SPACE, gc_reason); 682 mark_compact_collector_.SetFlags(kNoGCFlags); 683 } 684 685 686 void Heap::CollectAllAvailableGarbage(const char* gc_reason) { 687 // Since we are ignoring the return value, the exact choice of space does 688 // not matter, so long as we do not specify NEW_SPACE, which would not 689 // cause a full GC. 690 // Major GC would invoke weak handle callbacks on weakly reachable 691 // handles, but won't collect weakly reachable objects until next 692 // major GC. Therefore if we collect aggressively and weak handle callback 693 // has been invoked, we rerun major GC to release objects which become 694 // garbage. 695 // Note: as weak callbacks can execute arbitrary code, we cannot 696 // hope that eventually there will be no weak callbacks invocations. 697 // Therefore stop recollecting after several attempts. 698 if (isolate()->concurrent_recompilation_enabled()) { 699 // The optimizing compiler may be unnecessarily holding on to memory. 700 DisallowHeapAllocation no_recursive_gc; 701 isolate()->optimizing_compiler_thread()->Flush(); 702 } 703 mark_compact_collector()->SetFlags(kMakeHeapIterableMask | 704 kReduceMemoryFootprintMask); 705 isolate_->compilation_cache()->Clear(); 706 const int kMaxNumberOfAttempts = 7; 707 const int kMinNumberOfAttempts = 2; 708 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { 709 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR, gc_reason, NULL) && 710 attempt + 1 >= kMinNumberOfAttempts) { 711 break; 712 } 713 } 714 mark_compact_collector()->SetFlags(kNoGCFlags); 715 new_space_.Shrink(); 716 UncommitFromSpace(); 717 incremental_marking()->UncommitMarkingDeque(); 718 } 719 720 721 bool Heap::CollectGarbage(AllocationSpace space, 722 GarbageCollector collector, 723 const char* gc_reason, 724 const char* collector_reason) { 725 // The VM is in the GC state until exiting this function. 726 VMState<GC> state(isolate_); 727 728 #ifdef DEBUG 729 // Reset the allocation timeout to the GC interval, but make sure to 730 // allow at least a few allocations after a collection. The reason 731 // for this is that we have a lot of allocation sequences and we 732 // assume that a garbage collection will allow the subsequent 733 // allocation attempts to go through. 734 allocation_timeout_ = Max(6, FLAG_gc_interval); 735 #endif 736 737 if (collector == SCAVENGER && !incremental_marking()->IsStopped()) { 738 if (FLAG_trace_incremental_marking) { 739 PrintF("[IncrementalMarking] Scavenge during marking.\n"); 740 } 741 } 742 743 if (collector == MARK_COMPACTOR && 744 !mark_compact_collector()->abort_incremental_marking() && 745 !incremental_marking()->IsStopped() && 746 !incremental_marking()->should_hurry() && 747 FLAG_incremental_marking_steps) { 748 // Make progress in incremental marking. 749 const intptr_t kStepSizeWhenDelayedByScavenge = 1 * MB; 750 incremental_marking()->Step(kStepSizeWhenDelayedByScavenge, 751 IncrementalMarking::NO_GC_VIA_STACK_GUARD); 752 if (!incremental_marking()->IsComplete()) { 753 if (FLAG_trace_incremental_marking) { 754 PrintF("[IncrementalMarking] Delaying MarkSweep.\n"); 755 } 756 collector = SCAVENGER; 757 collector_reason = "incremental marking delaying mark-sweep"; 758 } 759 } 760 761 bool next_gc_likely_to_collect_more = false; 762 763 { GCTracer tracer(this, gc_reason, collector_reason); 764 ASSERT(AllowHeapAllocation::IsAllowed()); 765 DisallowHeapAllocation no_allocation_during_gc; 766 GarbageCollectionPrologue(); 767 // The GC count was incremented in the prologue. Tell the tracer about 768 // it. 769 tracer.set_gc_count(gc_count_); 770 771 // Tell the tracer which collector we've selected. 772 tracer.set_collector(collector); 773 774 { 775 HistogramTimerScope histogram_timer_scope( 776 (collector == SCAVENGER) ? isolate_->counters()->gc_scavenger() 777 : isolate_->counters()->gc_compactor()); 778 next_gc_likely_to_collect_more = 779 PerformGarbageCollection(collector, &tracer); 780 } 781 782 GarbageCollectionEpilogue(); 783 } 784 785 // Start incremental marking for the next cycle. The heap snapshot 786 // generator needs incremental marking to stay off after it aborted. 787 if (!mark_compact_collector()->abort_incremental_marking() && 788 incremental_marking()->IsStopped() && 789 incremental_marking()->WorthActivating() && 790 NextGCIsLikelyToBeFull()) { 791 incremental_marking()->Start(); 792 } 793 794 return next_gc_likely_to_collect_more; 795 } 796 797 798 int Heap::NotifyContextDisposed() { 799 if (isolate()->concurrent_recompilation_enabled()) { 800 // Flush the queued recompilation tasks. 801 isolate()->optimizing_compiler_thread()->Flush(); 802 } 803 flush_monomorphic_ics_ = true; 804 AgeInlineCaches(); 805 return ++contexts_disposed_; 806 } 807 808 809 void Heap::PerformScavenge() { 810 GCTracer tracer(this, NULL, NULL); 811 if (incremental_marking()->IsStopped()) { 812 PerformGarbageCollection(SCAVENGER, &tracer); 813 } else { 814 PerformGarbageCollection(MARK_COMPACTOR, &tracer); 815 } 816 } 817 818 819 void Heap::MoveElements(FixedArray* array, 820 int dst_index, 821 int src_index, 822 int len) { 823 if (len == 0) return; 824 825 ASSERT(array->map() != fixed_cow_array_map()); 826 Object** dst_objects = array->data_start() + dst_index; 827 OS::MemMove(dst_objects, 828 array->data_start() + src_index, 829 len * kPointerSize); 830 if (!InNewSpace(array)) { 831 for (int i = 0; i < len; i++) { 832 // TODO(hpayer): check store buffer for entries 833 if (InNewSpace(dst_objects[i])) { 834 RecordWrite(array->address(), array->OffsetOfElementAt(dst_index + i)); 835 } 836 } 837 } 838 incremental_marking()->RecordWrites(array); 839 } 840 841 842 #ifdef VERIFY_HEAP 843 // Helper class for verifying the string table. 844 class StringTableVerifier : public ObjectVisitor { 845 public: 846 void VisitPointers(Object** start, Object** end) { 847 // Visit all HeapObject pointers in [start, end). 848 for (Object** p = start; p < end; p++) { 849 if ((*p)->IsHeapObject()) { 850 // Check that the string is actually internalized. 851 CHECK((*p)->IsTheHole() || (*p)->IsUndefined() || 852 (*p)->IsInternalizedString()); 853 } 854 } 855 } 856 }; 857 858 859 static void VerifyStringTable(Heap* heap) { 860 StringTableVerifier verifier; 861 heap->string_table()->IterateElements(&verifier); 862 } 863 #endif // VERIFY_HEAP 864 865 866 static bool AbortIncrementalMarkingAndCollectGarbage( 867 Heap* heap, 868 AllocationSpace space, 869 const char* gc_reason = NULL) { 870 heap->mark_compact_collector()->SetFlags(Heap::kAbortIncrementalMarkingMask); 871 bool result = heap->CollectGarbage(space, gc_reason); 872 heap->mark_compact_collector()->SetFlags(Heap::kNoGCFlags); 873 return result; 874 } 875 876 877 void Heap::ReserveSpace(int *sizes, Address *locations_out) { 878 bool gc_performed = true; 879 int counter = 0; 880 static const int kThreshold = 20; 881 while (gc_performed && counter++ < kThreshold) { 882 gc_performed = false; 883 ASSERT(NEW_SPACE == FIRST_PAGED_SPACE - 1); 884 for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) { 885 if (sizes[space] != 0) { 886 MaybeObject* allocation; 887 if (space == NEW_SPACE) { 888 allocation = new_space()->AllocateRaw(sizes[space]); 889 } else { 890 allocation = paged_space(space)->AllocateRaw(sizes[space]); 891 } 892 FreeListNode* node; 893 if (!allocation->To<FreeListNode>(&node)) { 894 if (space == NEW_SPACE) { 895 Heap::CollectGarbage(NEW_SPACE, 896 "failed to reserve space in the new space"); 897 } else { 898 AbortIncrementalMarkingAndCollectGarbage( 899 this, 900 static_cast<AllocationSpace>(space), 901 "failed to reserve space in paged space"); 902 } 903 gc_performed = true; 904 break; 905 } else { 906 // Mark with a free list node, in case we have a GC before 907 // deserializing. 908 node->set_size(this, sizes[space]); 909 locations_out[space] = node->address(); 910 } 911 } 912 } 913 } 914 915 if (gc_performed) { 916 // Failed to reserve the space after several attempts. 917 V8::FatalProcessOutOfMemory("Heap::ReserveSpace"); 918 } 919 } 920 921 922 void Heap::EnsureFromSpaceIsCommitted() { 923 if (new_space_.CommitFromSpaceIfNeeded()) return; 924 925 // Committing memory to from space failed. 926 // Memory is exhausted and we will die. 927 V8::FatalProcessOutOfMemory("Committing semi space failed."); 928 } 929 930 931 void Heap::ClearJSFunctionResultCaches() { 932 if (isolate_->bootstrapper()->IsActive()) return; 933 934 Object* context = native_contexts_list_; 935 while (!context->IsUndefined()) { 936 // Get the caches for this context. GC can happen when the context 937 // is not fully initialized, so the caches can be undefined. 938 Object* caches_or_undefined = 939 Context::cast(context)->get(Context::JSFUNCTION_RESULT_CACHES_INDEX); 940 if (!caches_or_undefined->IsUndefined()) { 941 FixedArray* caches = FixedArray::cast(caches_or_undefined); 942 // Clear the caches: 943 int length = caches->length(); 944 for (int i = 0; i < length; i++) { 945 JSFunctionResultCache::cast(caches->get(i))->Clear(); 946 } 947 } 948 // Get the next context: 949 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); 950 } 951 } 952 953 954 void Heap::ClearNormalizedMapCaches() { 955 if (isolate_->bootstrapper()->IsActive() && 956 !incremental_marking()->IsMarking()) { 957 return; 958 } 959 960 Object* context = native_contexts_list_; 961 while (!context->IsUndefined()) { 962 // GC can happen when the context is not fully initialized, 963 // so the cache can be undefined. 964 Object* cache = 965 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX); 966 if (!cache->IsUndefined()) { 967 NormalizedMapCache::cast(cache)->Clear(); 968 } 969 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); 970 } 971 } 972 973 974 void Heap::UpdateSurvivalRateTrend(int start_new_space_size) { 975 if (start_new_space_size == 0) return; 976 977 double survival_rate = 978 (static_cast<double>(young_survivors_after_last_gc_) * 100) / 979 start_new_space_size; 980 981 if (survival_rate > kYoungSurvivalRateHighThreshold) { 982 high_survival_rate_period_length_++; 983 } else { 984 high_survival_rate_period_length_ = 0; 985 } 986 987 if (survival_rate < kYoungSurvivalRateLowThreshold) { 988 low_survival_rate_period_length_++; 989 } else { 990 low_survival_rate_period_length_ = 0; 991 } 992 993 double survival_rate_diff = survival_rate_ - survival_rate; 994 995 if (survival_rate_diff > kYoungSurvivalRateAllowedDeviation) { 996 set_survival_rate_trend(DECREASING); 997 } else if (survival_rate_diff < -kYoungSurvivalRateAllowedDeviation) { 998 set_survival_rate_trend(INCREASING); 999 } else { 1000 set_survival_rate_trend(STABLE); 1001 } 1002 1003 survival_rate_ = survival_rate; 1004 } 1005 1006 bool Heap::PerformGarbageCollection(GarbageCollector collector, 1007 GCTracer* tracer) { 1008 bool next_gc_likely_to_collect_more = false; 1009 1010 if (collector != SCAVENGER) { 1011 PROFILE(isolate_, CodeMovingGCEvent()); 1012 } 1013 1014 #ifdef VERIFY_HEAP 1015 if (FLAG_verify_heap) { 1016 VerifyStringTable(this); 1017 } 1018 #endif 1019 1020 GCType gc_type = 1021 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge; 1022 1023 { 1024 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); 1025 VMState<EXTERNAL> state(isolate_); 1026 HandleScope handle_scope(isolate_); 1027 CallGCPrologueCallbacks(gc_type, kNoGCCallbackFlags); 1028 } 1029 1030 EnsureFromSpaceIsCommitted(); 1031 1032 int start_new_space_size = Heap::new_space()->SizeAsInt(); 1033 1034 if (IsHighSurvivalRate()) { 1035 // We speed up the incremental marker if it is running so that it 1036 // does not fall behind the rate of promotion, which would cause a 1037 // constantly growing old space. 1038 incremental_marking()->NotifyOfHighPromotionRate(); 1039 } 1040 1041 if (collector == MARK_COMPACTOR) { 1042 // Perform mark-sweep with optional compaction. 1043 MarkCompact(tracer); 1044 sweep_generation_++; 1045 1046 UpdateSurvivalRateTrend(start_new_space_size); 1047 1048 size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSizeOfObjects(); 1049 1050 old_generation_allocation_limit_ = 1051 OldGenerationAllocationLimit(size_of_old_gen_at_last_old_space_gc_); 1052 1053 old_gen_exhausted_ = false; 1054 } else { 1055 tracer_ = tracer; 1056 Scavenge(); 1057 tracer_ = NULL; 1058 1059 UpdateSurvivalRateTrend(start_new_space_size); 1060 } 1061 1062 if (!new_space_high_promotion_mode_active_ && 1063 new_space_.Capacity() == new_space_.MaximumCapacity() && 1064 IsStableOrIncreasingSurvivalTrend() && 1065 IsHighSurvivalRate()) { 1066 // Stable high survival rates even though young generation is at 1067 // maximum capacity indicates that most objects will be promoted. 1068 // To decrease scavenger pauses and final mark-sweep pauses, we 1069 // have to limit maximal capacity of the young generation. 1070 SetNewSpaceHighPromotionModeActive(true); 1071 if (FLAG_trace_gc) { 1072 PrintPID("Limited new space size due to high promotion rate: %d MB\n", 1073 new_space_.InitialCapacity() / MB); 1074 } 1075 // Support for global pre-tenuring uses the high promotion mode as a 1076 // heuristic indicator of whether to pretenure or not, we trigger 1077 // deoptimization here to take advantage of pre-tenuring as soon as 1078 // possible. 1079 if (FLAG_pretenuring) { 1080 isolate_->stack_guard()->FullDeopt(); 1081 } 1082 } else if (new_space_high_promotion_mode_active_ && 1083 IsStableOrDecreasingSurvivalTrend() && 1084 IsLowSurvivalRate()) { 1085 // Decreasing low survival rates might indicate that the above high 1086 // promotion mode is over and we should allow the young generation 1087 // to grow again. 1088 SetNewSpaceHighPromotionModeActive(false); 1089 if (FLAG_trace_gc) { 1090 PrintPID("Unlimited new space size due to low promotion rate: %d MB\n", 1091 new_space_.MaximumCapacity() / MB); 1092 } 1093 // Trigger deoptimization here to turn off pre-tenuring as soon as 1094 // possible. 1095 if (FLAG_pretenuring) { 1096 isolate_->stack_guard()->FullDeopt(); 1097 } 1098 } 1099 1100 if (new_space_high_promotion_mode_active_ && 1101 new_space_.Capacity() > new_space_.InitialCapacity()) { 1102 new_space_.Shrink(); 1103 } 1104 1105 isolate_->counters()->objs_since_last_young()->Set(0); 1106 1107 // Callbacks that fire after this point might trigger nested GCs and 1108 // restart incremental marking, the assertion can't be moved down. 1109 ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped()); 1110 1111 gc_post_processing_depth_++; 1112 { AllowHeapAllocation allow_allocation; 1113 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); 1114 next_gc_likely_to_collect_more = 1115 isolate_->global_handles()->PostGarbageCollectionProcessing( 1116 collector, tracer); 1117 } 1118 gc_post_processing_depth_--; 1119 1120 isolate_->eternal_handles()->PostGarbageCollectionProcessing(this); 1121 1122 // Update relocatables. 1123 Relocatable::PostGarbageCollectionProcessing(isolate_); 1124 1125 if (collector == MARK_COMPACTOR) { 1126 // Register the amount of external allocated memory. 1127 amount_of_external_allocated_memory_at_last_global_gc_ = 1128 amount_of_external_allocated_memory_; 1129 } 1130 1131 { 1132 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); 1133 VMState<EXTERNAL> state(isolate_); 1134 HandleScope handle_scope(isolate_); 1135 CallGCEpilogueCallbacks(gc_type); 1136 } 1137 1138 #ifdef VERIFY_HEAP 1139 if (FLAG_verify_heap) { 1140 VerifyStringTable(this); 1141 } 1142 #endif 1143 1144 return next_gc_likely_to_collect_more; 1145 } 1146 1147 1148 void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) { 1149 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { 1150 if (gc_type & gc_prologue_callbacks_[i].gc_type) { 1151 if (!gc_prologue_callbacks_[i].pass_isolate_) { 1152 v8::GCPrologueCallback callback = 1153 reinterpret_cast<v8::GCPrologueCallback>( 1154 gc_prologue_callbacks_[i].callback); 1155 callback(gc_type, flags); 1156 } else { 1157 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate()); 1158 gc_prologue_callbacks_[i].callback(isolate, gc_type, flags); 1159 } 1160 } 1161 } 1162 } 1163 1164 1165 void Heap::CallGCEpilogueCallbacks(GCType gc_type) { 1166 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) { 1167 if (gc_type & gc_epilogue_callbacks_[i].gc_type) { 1168 if (!gc_epilogue_callbacks_[i].pass_isolate_) { 1169 v8::GCPrologueCallback callback = 1170 reinterpret_cast<v8::GCPrologueCallback>( 1171 gc_epilogue_callbacks_[i].callback); 1172 callback(gc_type, kNoGCCallbackFlags); 1173 } else { 1174 v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate()); 1175 gc_epilogue_callbacks_[i].callback( 1176 isolate, gc_type, kNoGCCallbackFlags); 1177 } 1178 } 1179 } 1180 } 1181 1182 1183 void Heap::MarkCompact(GCTracer* tracer) { 1184 gc_state_ = MARK_COMPACT; 1185 LOG(isolate_, ResourceEvent("markcompact", "begin")); 1186 1187 mark_compact_collector_.Prepare(tracer); 1188 1189 ms_count_++; 1190 tracer->set_full_gc_count(ms_count_); 1191 1192 MarkCompactPrologue(); 1193 1194 mark_compact_collector_.CollectGarbage(); 1195 1196 LOG(isolate_, ResourceEvent("markcompact", "end")); 1197 1198 gc_state_ = NOT_IN_GC; 1199 1200 isolate_->counters()->objs_since_last_full()->Set(0); 1201 1202 flush_monomorphic_ics_ = false; 1203 } 1204 1205 1206 void Heap::MarkCompactPrologue() { 1207 // At any old GC clear the keyed lookup cache to enable collection of unused 1208 // maps. 1209 isolate_->keyed_lookup_cache()->Clear(); 1210 isolate_->context_slot_cache()->Clear(); 1211 isolate_->descriptor_lookup_cache()->Clear(); 1212 RegExpResultsCache::Clear(string_split_cache()); 1213 RegExpResultsCache::Clear(regexp_multiple_cache()); 1214 1215 isolate_->compilation_cache()->MarkCompactPrologue(); 1216 1217 CompletelyClearInstanceofCache(); 1218 1219 FlushNumberStringCache(); 1220 if (FLAG_cleanup_code_caches_at_gc) { 1221 polymorphic_code_cache()->set_cache(undefined_value()); 1222 } 1223 1224 ClearNormalizedMapCaches(); 1225 } 1226 1227 1228 // Helper class for copying HeapObjects 1229 class ScavengeVisitor: public ObjectVisitor { 1230 public: 1231 explicit ScavengeVisitor(Heap* heap) : heap_(heap) {} 1232 1233 void VisitPointer(Object** p) { ScavengePointer(p); } 1234 1235 void VisitPointers(Object** start, Object** end) { 1236 // Copy all HeapObject pointers in [start, end) 1237 for (Object** p = start; p < end; p++) ScavengePointer(p); 1238 } 1239 1240 private: 1241 void ScavengePointer(Object** p) { 1242 Object* object = *p; 1243 if (!heap_->InNewSpace(object)) return; 1244 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), 1245 reinterpret_cast<HeapObject*>(object)); 1246 } 1247 1248 Heap* heap_; 1249 }; 1250 1251 1252 #ifdef VERIFY_HEAP 1253 // Visitor class to verify pointers in code or data space do not point into 1254 // new space. 1255 class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor { 1256 public: 1257 explicit VerifyNonPointerSpacePointersVisitor(Heap* heap) : heap_(heap) {} 1258 void VisitPointers(Object** start, Object**end) { 1259 for (Object** current = start; current < end; current++) { 1260 if ((*current)->IsHeapObject()) { 1261 CHECK(!heap_->InNewSpace(HeapObject::cast(*current))); 1262 } 1263 } 1264 } 1265 1266 private: 1267 Heap* heap_; 1268 }; 1269 1270 1271 static void VerifyNonPointerSpacePointers(Heap* heap) { 1272 // Verify that there are no pointers to new space in spaces where we 1273 // do not expect them. 1274 VerifyNonPointerSpacePointersVisitor v(heap); 1275 HeapObjectIterator code_it(heap->code_space()); 1276 for (HeapObject* object = code_it.Next(); 1277 object != NULL; object = code_it.Next()) 1278 object->Iterate(&v); 1279 1280 // The old data space was normally swept conservatively so that the iterator 1281 // doesn't work, so we normally skip the next bit. 1282 if (!heap->old_data_space()->was_swept_conservatively()) { 1283 HeapObjectIterator data_it(heap->old_data_space()); 1284 for (HeapObject* object = data_it.Next(); 1285 object != NULL; object = data_it.Next()) 1286 object->Iterate(&v); 1287 } 1288 } 1289 #endif // VERIFY_HEAP 1290 1291 1292 void Heap::CheckNewSpaceExpansionCriteria() { 1293 if (new_space_.Capacity() < new_space_.MaximumCapacity() && 1294 survived_since_last_expansion_ > new_space_.Capacity() && 1295 !new_space_high_promotion_mode_active_) { 1296 // Grow the size of new space if there is room to grow, enough data 1297 // has survived scavenge since the last expansion and we are not in 1298 // high promotion mode. 1299 new_space_.Grow(); 1300 survived_since_last_expansion_ = 0; 1301 } 1302 } 1303 1304 1305 static bool IsUnscavengedHeapObject(Heap* heap, Object** p) { 1306 return heap->InNewSpace(*p) && 1307 !HeapObject::cast(*p)->map_word().IsForwardingAddress(); 1308 } 1309 1310 1311 void Heap::ScavengeStoreBufferCallback( 1312 Heap* heap, 1313 MemoryChunk* page, 1314 StoreBufferEvent event) { 1315 heap->store_buffer_rebuilder_.Callback(page, event); 1316 } 1317 1318 1319 void StoreBufferRebuilder::Callback(MemoryChunk* page, StoreBufferEvent event) { 1320 if (event == kStoreBufferStartScanningPagesEvent) { 1321 start_of_current_page_ = NULL; 1322 current_page_ = NULL; 1323 } else if (event == kStoreBufferScanningPageEvent) { 1324 if (current_page_ != NULL) { 1325 // If this page already overflowed the store buffer during this iteration. 1326 if (current_page_->scan_on_scavenge()) { 1327 // Then we should wipe out the entries that have been added for it. 1328 store_buffer_->SetTop(start_of_current_page_); 1329 } else if (store_buffer_->Top() - start_of_current_page_ >= 1330 (store_buffer_->Limit() - store_buffer_->Top()) >> 2) { 1331 // Did we find too many pointers in the previous page? The heuristic is 1332 // that no page can take more then 1/5 the remaining slots in the store 1333 // buffer. 1334 current_page_->set_scan_on_scavenge(true); 1335 store_buffer_->SetTop(start_of_current_page_); 1336 } else { 1337 // In this case the page we scanned took a reasonable number of slots in 1338 // the store buffer. It has now been rehabilitated and is no longer 1339 // marked scan_on_scavenge. 1340 ASSERT(!current_page_->scan_on_scavenge()); 1341 } 1342 } 1343 start_of_current_page_ = store_buffer_->Top(); 1344 current_page_ = page; 1345 } else if (event == kStoreBufferFullEvent) { 1346 // The current page overflowed the store buffer again. Wipe out its entries 1347 // in the store buffer and mark it scan-on-scavenge again. This may happen 1348 // several times while scanning. 1349 if (current_page_ == NULL) { 1350 // Store Buffer overflowed while scanning promoted objects. These are not 1351 // in any particular page, though they are likely to be clustered by the 1352 // allocation routines. 1353 store_buffer_->EnsureSpace(StoreBuffer::kStoreBufferSize / 2); 1354 } else { 1355 // Store Buffer overflowed while scanning a particular old space page for 1356 // pointers to new space. 1357 ASSERT(current_page_ == page); 1358 ASSERT(page != NULL); 1359 current_page_->set_scan_on_scavenge(true); 1360 ASSERT(start_of_current_page_ != store_buffer_->Top()); 1361 store_buffer_->SetTop(start_of_current_page_); 1362 } 1363 } else { 1364 UNREACHABLE(); 1365 } 1366 } 1367 1368 1369 void PromotionQueue::Initialize() { 1370 // Assumes that a NewSpacePage exactly fits a number of promotion queue 1371 // entries (where each is a pair of intptr_t). This allows us to simplify 1372 // the test fpr when to switch pages. 1373 ASSERT((Page::kPageSize - MemoryChunk::kBodyOffset) % (2 * kPointerSize) 1374 == 0); 1375 limit_ = reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceStart()); 1376 front_ = rear_ = 1377 reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceEnd()); 1378 emergency_stack_ = NULL; 1379 guard_ = false; 1380 } 1381 1382 1383 void PromotionQueue::RelocateQueueHead() { 1384 ASSERT(emergency_stack_ == NULL); 1385 1386 Page* p = Page::FromAllocationTop(reinterpret_cast<Address>(rear_)); 1387 intptr_t* head_start = rear_; 1388 intptr_t* head_end = 1389 Min(front_, reinterpret_cast<intptr_t*>(p->area_end())); 1390 1391 int entries_count = 1392 static_cast<int>(head_end - head_start) / kEntrySizeInWords; 1393 1394 emergency_stack_ = new List<Entry>(2 * entries_count); 1395 1396 while (head_start != head_end) { 1397 int size = static_cast<int>(*(head_start++)); 1398 HeapObject* obj = reinterpret_cast<HeapObject*>(*(head_start++)); 1399 emergency_stack_->Add(Entry(obj, size)); 1400 } 1401 rear_ = head_end; 1402 } 1403 1404 1405 class ScavengeWeakObjectRetainer : public WeakObjectRetainer { 1406 public: 1407 explicit ScavengeWeakObjectRetainer(Heap* heap) : heap_(heap) { } 1408 1409 virtual Object* RetainAs(Object* object) { 1410 if (!heap_->InFromSpace(object)) { 1411 return object; 1412 } 1413 1414 MapWord map_word = HeapObject::cast(object)->map_word(); 1415 if (map_word.IsForwardingAddress()) { 1416 return map_word.ToForwardingAddress(); 1417 } 1418 return NULL; 1419 } 1420 1421 private: 1422 Heap* heap_; 1423 }; 1424 1425 1426 void Heap::Scavenge() { 1427 RelocationLock relocation_lock(this); 1428 1429 #ifdef VERIFY_HEAP 1430 if (FLAG_verify_heap) VerifyNonPointerSpacePointers(this); 1431 #endif 1432 1433 gc_state_ = SCAVENGE; 1434 1435 // Implements Cheney's copying algorithm 1436 LOG(isolate_, ResourceEvent("scavenge", "begin")); 1437 1438 // Clear descriptor cache. 1439 isolate_->descriptor_lookup_cache()->Clear(); 1440 1441 // Used for updating survived_since_last_expansion_ at function end. 1442 intptr_t survived_watermark = PromotedSpaceSizeOfObjects(); 1443 1444 CheckNewSpaceExpansionCriteria(); 1445 1446 SelectScavengingVisitorsTable(); 1447 1448 incremental_marking()->PrepareForScavenge(); 1449 1450 paged_space(OLD_DATA_SPACE)->EnsureSweeperProgress(new_space_.Size()); 1451 paged_space(OLD_POINTER_SPACE)->EnsureSweeperProgress(new_space_.Size()); 1452 1453 // Flip the semispaces. After flipping, to space is empty, from space has 1454 // live objects. 1455 new_space_.Flip(); 1456 new_space_.ResetAllocationInfo(); 1457 1458 // We need to sweep newly copied objects which can be either in the 1459 // to space or promoted to the old generation. For to-space 1460 // objects, we treat the bottom of the to space as a queue. Newly 1461 // copied and unswept objects lie between a 'front' mark and the 1462 // allocation pointer. 1463 // 1464 // Promoted objects can go into various old-generation spaces, and 1465 // can be allocated internally in the spaces (from the free list). 1466 // We treat the top of the to space as a queue of addresses of 1467 // promoted objects. The addresses of newly promoted and unswept 1468 // objects lie between a 'front' mark and a 'rear' mark that is 1469 // updated as a side effect of promoting an object. 1470 // 1471 // There is guaranteed to be enough room at the top of the to space 1472 // for the addresses of promoted objects: every object promoted 1473 // frees up its size in bytes from the top of the new space, and 1474 // objects are at least one pointer in size. 1475 Address new_space_front = new_space_.ToSpaceStart(); 1476 promotion_queue_.Initialize(); 1477 1478 #ifdef DEBUG 1479 store_buffer()->Clean(); 1480 #endif 1481 1482 ScavengeVisitor scavenge_visitor(this); 1483 // Copy roots. 1484 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE); 1485 1486 // Copy objects reachable from the old generation. 1487 { 1488 StoreBufferRebuildScope scope(this, 1489 store_buffer(), 1490 &ScavengeStoreBufferCallback); 1491 store_buffer()->IteratePointersToNewSpace(&ScavengeObject); 1492 } 1493 1494 // Copy objects reachable from simple cells by scavenging cell values 1495 // directly. 1496 HeapObjectIterator cell_iterator(cell_space_); 1497 for (HeapObject* heap_object = cell_iterator.Next(); 1498 heap_object != NULL; 1499 heap_object = cell_iterator.Next()) { 1500 if (heap_object->IsCell()) { 1501 Cell* cell = Cell::cast(heap_object); 1502 Address value_address = cell->ValueAddress(); 1503 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); 1504 } 1505 } 1506 1507 // Copy objects reachable from global property cells by scavenging global 1508 // property cell values directly. 1509 HeapObjectIterator js_global_property_cell_iterator(property_cell_space_); 1510 for (HeapObject* heap_object = js_global_property_cell_iterator.Next(); 1511 heap_object != NULL; 1512 heap_object = js_global_property_cell_iterator.Next()) { 1513 if (heap_object->IsPropertyCell()) { 1514 PropertyCell* cell = PropertyCell::cast(heap_object); 1515 Address value_address = cell->ValueAddress(); 1516 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address)); 1517 Address type_address = cell->TypeAddress(); 1518 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(type_address)); 1519 } 1520 } 1521 1522 // Copy objects reachable from the code flushing candidates list. 1523 MarkCompactCollector* collector = mark_compact_collector(); 1524 if (collector->is_code_flushing_enabled()) { 1525 collector->code_flusher()->IteratePointersToFromSpace(&scavenge_visitor); 1526 } 1527 1528 // Scavenge object reachable from the native contexts list directly. 1529 scavenge_visitor.VisitPointer(BitCast<Object**>(&native_contexts_list_)); 1530 1531 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); 1532 1533 while (isolate()->global_handles()->IterateObjectGroups( 1534 &scavenge_visitor, &IsUnscavengedHeapObject)) { 1535 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); 1536 } 1537 isolate()->global_handles()->RemoveObjectGroups(); 1538 isolate()->global_handles()->RemoveImplicitRefGroups(); 1539 1540 isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles( 1541 &IsUnscavengedHeapObject); 1542 isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots( 1543 &scavenge_visitor); 1544 new_space_front = DoScavenge(&scavenge_visitor, new_space_front); 1545 1546 UpdateNewSpaceReferencesInExternalStringTable( 1547 &UpdateNewSpaceReferenceInExternalStringTableEntry); 1548 1549 promotion_queue_.Destroy(); 1550 1551 if (!FLAG_watch_ic_patching) { 1552 isolate()->runtime_profiler()->UpdateSamplesAfterScavenge(); 1553 } 1554 incremental_marking()->UpdateMarkingDequeAfterScavenge(); 1555 1556 ScavengeWeakObjectRetainer weak_object_retainer(this); 1557 ProcessWeakReferences(&weak_object_retainer); 1558 1559 ASSERT(new_space_front == new_space_.top()); 1560 1561 // Set age mark. 1562 new_space_.set_age_mark(new_space_.top()); 1563 1564 new_space_.LowerInlineAllocationLimit( 1565 new_space_.inline_allocation_limit_step()); 1566 1567 // Update how much has survived scavenge. 1568 IncrementYoungSurvivorsCounter(static_cast<int>( 1569 (PromotedSpaceSizeOfObjects() - survived_watermark) + new_space_.Size())); 1570 1571 LOG(isolate_, ResourceEvent("scavenge", "end")); 1572 1573 gc_state_ = NOT_IN_GC; 1574 1575 scavenges_since_last_idle_round_++; 1576 } 1577 1578 1579 String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap, 1580 Object** p) { 1581 MapWord first_word = HeapObject::cast(*p)->map_word(); 1582 1583 if (!first_word.IsForwardingAddress()) { 1584 // Unreachable external string can be finalized. 1585 heap->FinalizeExternalString(String::cast(*p)); 1586 return NULL; 1587 } 1588 1589 // String is still reachable. 1590 return String::cast(first_word.ToForwardingAddress()); 1591 } 1592 1593 1594 void Heap::UpdateNewSpaceReferencesInExternalStringTable( 1595 ExternalStringTableUpdaterCallback updater_func) { 1596 #ifdef VERIFY_HEAP 1597 if (FLAG_verify_heap) { 1598 external_string_table_.Verify(); 1599 } 1600 #endif 1601 1602 if (external_string_table_.new_space_strings_.is_empty()) return; 1603 1604 Object** start = &external_string_table_.new_space_strings_[0]; 1605 Object** end = start + external_string_table_.new_space_strings_.length(); 1606 Object** last = start; 1607 1608 for (Object** p = start; p < end; ++p) { 1609 ASSERT(InFromSpace(*p)); 1610 String* target = updater_func(this, p); 1611 1612 if (target == NULL) continue; 1613 1614 ASSERT(target->IsExternalString()); 1615 1616 if (InNewSpace(target)) { 1617 // String is still in new space. Update the table entry. 1618 *last = target; 1619 ++last; 1620 } else { 1621 // String got promoted. Move it to the old string list. 1622 external_string_table_.AddOldString(target); 1623 } 1624 } 1625 1626 ASSERT(last <= end); 1627 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start)); 1628 } 1629 1630 1631 void Heap::UpdateReferencesInExternalStringTable( 1632 ExternalStringTableUpdaterCallback updater_func) { 1633 1634 // Update old space string references. 1635 if (external_string_table_.old_space_strings_.length() > 0) { 1636 Object** start = &external_string_table_.old_space_strings_[0]; 1637 Object** end = start + external_string_table_.old_space_strings_.length(); 1638 for (Object** p = start; p < end; ++p) *p = updater_func(this, p); 1639 } 1640 1641 UpdateNewSpaceReferencesInExternalStringTable(updater_func); 1642 } 1643 1644 1645 template <class T> 1646 struct WeakListVisitor; 1647 1648 1649 template <class T> 1650 static Object* VisitWeakList(Heap* heap, 1651 Object* list, 1652 WeakObjectRetainer* retainer, 1653 bool record_slots) { 1654 Object* undefined = heap->undefined_value(); 1655 Object* head = undefined; 1656 T* tail = NULL; 1657 MarkCompactCollector* collector = heap->mark_compact_collector(); 1658 while (list != undefined) { 1659 // Check whether to keep the candidate in the list. 1660 T* candidate = reinterpret_cast<T*>(list); 1661 Object* retained = retainer->RetainAs(list); 1662 if (retained != NULL) { 1663 if (head == undefined) { 1664 // First element in the list. 1665 head = retained; 1666 } else { 1667 // Subsequent elements in the list. 1668 ASSERT(tail != NULL); 1669 WeakListVisitor<T>::SetWeakNext(tail, retained); 1670 if (record_slots) { 1671 Object** next_slot = 1672 HeapObject::RawField(tail, WeakListVisitor<T>::WeakNextOffset()); 1673 collector->RecordSlot(next_slot, next_slot, retained); 1674 } 1675 } 1676 // Retained object is new tail. 1677 ASSERT(!retained->IsUndefined()); 1678 candidate = reinterpret_cast<T*>(retained); 1679 tail = candidate; 1680 1681 1682 // tail is a live object, visit it. 1683 WeakListVisitor<T>::VisitLiveObject( 1684 heap, tail, retainer, record_slots); 1685 } else { 1686 WeakListVisitor<T>::VisitPhantomObject(heap, candidate); 1687 } 1688 1689 // Move to next element in the list. 1690 list = WeakListVisitor<T>::WeakNext(candidate); 1691 } 1692 1693 // Terminate the list if there is one or more elements. 1694 if (tail != NULL) { 1695 WeakListVisitor<T>::SetWeakNext(tail, undefined); 1696 } 1697 return head; 1698 } 1699 1700 1701 template<> 1702 struct WeakListVisitor<JSFunction> { 1703 static void SetWeakNext(JSFunction* function, Object* next) { 1704 function->set_next_function_link(next); 1705 } 1706 1707 static Object* WeakNext(JSFunction* function) { 1708 return function->next_function_link(); 1709 } 1710 1711 static int WeakNextOffset() { 1712 return JSFunction::kNextFunctionLinkOffset; 1713 } 1714 1715 static void VisitLiveObject(Heap*, JSFunction*, 1716 WeakObjectRetainer*, bool) { 1717 } 1718 1719 static void VisitPhantomObject(Heap*, JSFunction*) { 1720 } 1721 }; 1722 1723 1724 template<> 1725 struct WeakListVisitor<Code> { 1726 static void SetWeakNext(Code* code, Object* next) { 1727 code->set_next_code_link(next); 1728 } 1729 1730 static Object* WeakNext(Code* code) { 1731 return code->next_code_link(); 1732 } 1733 1734 static int WeakNextOffset() { 1735 return Code::kNextCodeLinkOffset; 1736 } 1737 1738 static void VisitLiveObject(Heap*, Code*, 1739 WeakObjectRetainer*, bool) { 1740 } 1741 1742 static void VisitPhantomObject(Heap*, Code*) { 1743 } 1744 }; 1745 1746 1747 template<> 1748 struct WeakListVisitor<Context> { 1749 static void SetWeakNext(Context* context, Object* next) { 1750 context->set(Context::NEXT_CONTEXT_LINK, 1751 next, 1752 UPDATE_WRITE_BARRIER); 1753 } 1754 1755 static Object* WeakNext(Context* context) { 1756 return context->get(Context::NEXT_CONTEXT_LINK); 1757 } 1758 1759 static void VisitLiveObject(Heap* heap, 1760 Context* context, 1761 WeakObjectRetainer* retainer, 1762 bool record_slots) { 1763 // Process the three weak lists linked off the context. 1764 DoWeakList<JSFunction>(heap, context, retainer, record_slots, 1765 Context::OPTIMIZED_FUNCTIONS_LIST); 1766 DoWeakList<Code>(heap, context, retainer, record_slots, 1767 Context::OPTIMIZED_CODE_LIST); 1768 DoWeakList<Code>(heap, context, retainer, record_slots, 1769 Context::DEOPTIMIZED_CODE_LIST); 1770 } 1771 1772 template<class T> 1773 static void DoWeakList(Heap* heap, 1774 Context* context, 1775 WeakObjectRetainer* retainer, 1776 bool record_slots, 1777 int index) { 1778 // Visit the weak list, removing dead intermediate elements. 1779 Object* list_head = VisitWeakList<T>(heap, context->get(index), retainer, 1780 record_slots); 1781 1782 // Update the list head. 1783 context->set(index, list_head, UPDATE_WRITE_BARRIER); 1784 1785 if (record_slots) { 1786 // Record the updated slot if necessary. 1787 Object** head_slot = HeapObject::RawField( 1788 context, FixedArray::SizeFor(index)); 1789 heap->mark_compact_collector()->RecordSlot( 1790 head_slot, head_slot, list_head); 1791 } 1792 } 1793 1794 static void VisitPhantomObject(Heap*, Context*) { 1795 } 1796 1797 static int WeakNextOffset() { 1798 return FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK); 1799 } 1800 }; 1801 1802 1803 void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) { 1804 // We don't record weak slots during marking or scavenges. 1805 // Instead we do it once when we complete mark-compact cycle. 1806 // Note that write barrier has no effect if we are already in the middle of 1807 // compacting mark-sweep cycle and we have to record slots manually. 1808 bool record_slots = 1809 gc_state() == MARK_COMPACT && 1810 mark_compact_collector()->is_compacting(); 1811 ProcessArrayBuffers(retainer, record_slots); 1812 ProcessNativeContexts(retainer, record_slots); 1813 // TODO(mvstanton): AllocationSites only need to be processed during 1814 // MARK_COMPACT, as they live in old space. Verify and address. 1815 ProcessAllocationSites(retainer, record_slots); 1816 } 1817 1818 void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer, 1819 bool record_slots) { 1820 Object* head = 1821 VisitWeakList<Context>( 1822 this, native_contexts_list(), retainer, record_slots); 1823 // Update the head of the list of contexts. 1824 native_contexts_list_ = head; 1825 } 1826 1827 1828 template<> 1829 struct WeakListVisitor<JSArrayBufferView> { 1830 static void SetWeakNext(JSArrayBufferView* obj, Object* next) { 1831 obj->set_weak_next(next); 1832 } 1833 1834 static Object* WeakNext(JSArrayBufferView* obj) { 1835 return obj->weak_next(); 1836 } 1837 1838 static void VisitLiveObject(Heap*, 1839 JSArrayBufferView* obj, 1840 WeakObjectRetainer* retainer, 1841 bool record_slots) {} 1842 1843 static void VisitPhantomObject(Heap*, JSArrayBufferView*) {} 1844 1845 static int WeakNextOffset() { 1846 return JSArrayBufferView::kWeakNextOffset; 1847 } 1848 }; 1849 1850 1851 template<> 1852 struct WeakListVisitor<JSArrayBuffer> { 1853 static void SetWeakNext(JSArrayBuffer* obj, Object* next) { 1854 obj->set_weak_next(next); 1855 } 1856 1857 static Object* WeakNext(JSArrayBuffer* obj) { 1858 return obj->weak_next(); 1859 } 1860 1861 static void VisitLiveObject(Heap* heap, 1862 JSArrayBuffer* array_buffer, 1863 WeakObjectRetainer* retainer, 1864 bool record_slots) { 1865 Object* typed_array_obj = 1866 VisitWeakList<JSArrayBufferView>( 1867 heap, 1868 array_buffer->weak_first_view(), 1869 retainer, record_slots); 1870 array_buffer->set_weak_first_view(typed_array_obj); 1871 if (typed_array_obj != heap->undefined_value() && record_slots) { 1872 Object** slot = HeapObject::RawField( 1873 array_buffer, JSArrayBuffer::kWeakFirstViewOffset); 1874 heap->mark_compact_collector()->RecordSlot(slot, slot, typed_array_obj); 1875 } 1876 } 1877 1878 static void VisitPhantomObject(Heap* heap, JSArrayBuffer* phantom) { 1879 Runtime::FreeArrayBuffer(heap->isolate(), phantom); 1880 } 1881 1882 static int WeakNextOffset() { 1883 return JSArrayBuffer::kWeakNextOffset; 1884 } 1885 }; 1886 1887 1888 void Heap::ProcessArrayBuffers(WeakObjectRetainer* retainer, 1889 bool record_slots) { 1890 Object* array_buffer_obj = 1891 VisitWeakList<JSArrayBuffer>(this, 1892 array_buffers_list(), 1893 retainer, record_slots); 1894 set_array_buffers_list(array_buffer_obj); 1895 } 1896 1897 1898 void Heap::TearDownArrayBuffers() { 1899 Object* undefined = undefined_value(); 1900 for (Object* o = array_buffers_list(); o != undefined;) { 1901 JSArrayBuffer* buffer = JSArrayBuffer::cast(o); 1902 Runtime::FreeArrayBuffer(isolate(), buffer); 1903 o = buffer->weak_next(); 1904 } 1905 array_buffers_list_ = undefined; 1906 } 1907 1908 1909 template<> 1910 struct WeakListVisitor<AllocationSite> { 1911 static void SetWeakNext(AllocationSite* obj, Object* next) { 1912 obj->set_weak_next(next); 1913 } 1914 1915 static Object* WeakNext(AllocationSite* obj) { 1916 return obj->weak_next(); 1917 } 1918 1919 static void VisitLiveObject(Heap* heap, 1920 AllocationSite* site, 1921 WeakObjectRetainer* retainer, 1922 bool record_slots) {} 1923 1924 static void VisitPhantomObject(Heap* heap, AllocationSite* phantom) {} 1925 1926 static int WeakNextOffset() { 1927 return AllocationSite::kWeakNextOffset; 1928 } 1929 }; 1930 1931 1932 void Heap::ProcessAllocationSites(WeakObjectRetainer* retainer, 1933 bool record_slots) { 1934 Object* allocation_site_obj = 1935 VisitWeakList<AllocationSite>(this, 1936 allocation_sites_list(), 1937 retainer, record_slots); 1938 set_allocation_sites_list(allocation_site_obj); 1939 } 1940 1941 1942 void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) { 1943 DisallowHeapAllocation no_allocation; 1944 1945 // Both the external string table and the string table may contain 1946 // external strings, but neither lists them exhaustively, nor is the 1947 // intersection set empty. Therefore we iterate over the external string 1948 // table first, ignoring internalized strings, and then over the 1949 // internalized string table. 1950 1951 class ExternalStringTableVisitorAdapter : public ObjectVisitor { 1952 public: 1953 explicit ExternalStringTableVisitorAdapter( 1954 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {} 1955 virtual void VisitPointers(Object** start, Object** end) { 1956 for (Object** p = start; p < end; p++) { 1957 // Visit non-internalized external strings, 1958 // since internalized strings are listed in the string table. 1959 if (!(*p)->IsInternalizedString()) { 1960 ASSERT((*p)->IsExternalString()); 1961 visitor_->VisitExternalString(Utils::ToLocal( 1962 Handle<String>(String::cast(*p)))); 1963 } 1964 } 1965 } 1966 private: 1967 v8::ExternalResourceVisitor* visitor_; 1968 } external_string_table_visitor(visitor); 1969 1970 external_string_table_.Iterate(&external_string_table_visitor); 1971 1972 class StringTableVisitorAdapter : public ObjectVisitor { 1973 public: 1974 explicit StringTableVisitorAdapter( 1975 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {} 1976 virtual void VisitPointers(Object** start, Object** end) { 1977 for (Object** p = start; p < end; p++) { 1978 if ((*p)->IsExternalString()) { 1979 ASSERT((*p)->IsInternalizedString()); 1980 visitor_->VisitExternalString(Utils::ToLocal( 1981 Handle<String>(String::cast(*p)))); 1982 } 1983 } 1984 } 1985 private: 1986 v8::ExternalResourceVisitor* visitor_; 1987 } string_table_visitor(visitor); 1988 1989 string_table()->IterateElements(&string_table_visitor); 1990 } 1991 1992 1993 class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> { 1994 public: 1995 static inline void VisitPointer(Heap* heap, Object** p) { 1996 Object* object = *p; 1997 if (!heap->InNewSpace(object)) return; 1998 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), 1999 reinterpret_cast<HeapObject*>(object)); 2000 } 2001 }; 2002 2003 2004 Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, 2005 Address new_space_front) { 2006 do { 2007 SemiSpace::AssertValidRange(new_space_front, new_space_.top()); 2008 // The addresses new_space_front and new_space_.top() define a 2009 // queue of unprocessed copied objects. Process them until the 2010 // queue is empty. 2011 while (new_space_front != new_space_.top()) { 2012 if (!NewSpacePage::IsAtEnd(new_space_front)) { 2013 HeapObject* object = HeapObject::FromAddress(new_space_front); 2014 new_space_front += 2015 NewSpaceScavenger::IterateBody(object->map(), object); 2016 } else { 2017 new_space_front = 2018 NewSpacePage::FromLimit(new_space_front)->next_page()->area_start(); 2019 } 2020 } 2021 2022 // Promote and process all the to-be-promoted objects. 2023 { 2024 StoreBufferRebuildScope scope(this, 2025 store_buffer(), 2026 &ScavengeStoreBufferCallback); 2027 while (!promotion_queue()->is_empty()) { 2028 HeapObject* target; 2029 int size; 2030 promotion_queue()->remove(&target, &size); 2031 2032 // Promoted object might be already partially visited 2033 // during old space pointer iteration. Thus we search specificly 2034 // for pointers to from semispace instead of looking for pointers 2035 // to new space. 2036 ASSERT(!target->IsMap()); 2037 IterateAndMarkPointersToFromSpace(target->address(), 2038 target->address() + size, 2039 &ScavengeObject); 2040 } 2041 } 2042 2043 // Take another spin if there are now unswept objects in new space 2044 // (there are currently no more unswept promoted objects). 2045 } while (new_space_front != new_space_.top()); 2046 2047 return new_space_front; 2048 } 2049 2050 2051 STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == 0); 2052 STATIC_ASSERT((ConstantPoolArray::kHeaderSize & kDoubleAlignmentMask) == 0); 2053 2054 2055 INLINE(static HeapObject* EnsureDoubleAligned(Heap* heap, 2056 HeapObject* object, 2057 int size)); 2058 2059 static HeapObject* EnsureDoubleAligned(Heap* heap, 2060 HeapObject* object, 2061 int size) { 2062 if ((OffsetFrom(object->address()) & kDoubleAlignmentMask) != 0) { 2063 heap->CreateFillerObjectAt(object->address(), kPointerSize); 2064 return HeapObject::FromAddress(object->address() + kPointerSize); 2065 } else { 2066 heap->CreateFillerObjectAt(object->address() + size - kPointerSize, 2067 kPointerSize); 2068 return object; 2069 } 2070 } 2071 2072 2073 enum LoggingAndProfiling { 2074 LOGGING_AND_PROFILING_ENABLED, 2075 LOGGING_AND_PROFILING_DISABLED 2076 }; 2077 2078 2079 enum MarksHandling { TRANSFER_MARKS, IGNORE_MARKS }; 2080 2081 2082 template<MarksHandling marks_handling, 2083 LoggingAndProfiling logging_and_profiling_mode> 2084 class ScavengingVisitor : public StaticVisitorBase { 2085 public: 2086 static void Initialize() { 2087 table_.Register(kVisitSeqOneByteString, &EvacuateSeqOneByteString); 2088 table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString); 2089 table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate); 2090 table_.Register(kVisitByteArray, &EvacuateByteArray); 2091 table_.Register(kVisitFixedArray, &EvacuateFixedArray); 2092 table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray); 2093 2094 table_.Register(kVisitNativeContext, 2095 &ObjectEvacuationStrategy<POINTER_OBJECT>:: 2096 template VisitSpecialized<Context::kSize>); 2097 2098 table_.Register(kVisitConsString, 2099 &ObjectEvacuationStrategy<POINTER_OBJECT>:: 2100 template VisitSpecialized<ConsString::kSize>); 2101 2102 table_.Register(kVisitSlicedString, 2103 &ObjectEvacuationStrategy<POINTER_OBJECT>:: 2104 template VisitSpecialized<SlicedString::kSize>); 2105 2106 table_.Register(kVisitSymbol, 2107 &ObjectEvacuationStrategy<POINTER_OBJECT>:: 2108 template VisitSpecialized<Symbol::kSize>); 2109 2110 table_.Register(kVisitSharedFunctionInfo, 2111 &ObjectEvacuationStrategy<POINTER_OBJECT>:: 2112 template VisitSpecialized<SharedFunctionInfo::kSize>); 2113 2114 table_.Register(kVisitJSWeakMap, 2115 &ObjectEvacuationStrategy<POINTER_OBJECT>:: 2116 Visit); 2117 2118 table_.Register(kVisitJSWeakSet, 2119 &ObjectEvacuationStrategy<POINTER_OBJECT>:: 2120 Visit); 2121 2122 table_.Register(kVisitJSArrayBuffer, 2123 &ObjectEvacuationStrategy<POINTER_OBJECT>:: 2124 Visit); 2125 2126 table_.Register(kVisitJSTypedArray, 2127 &ObjectEvacuationStrategy<POINTER_OBJECT>:: 2128 Visit); 2129 2130 table_.Register(kVisitJSDataView, 2131 &ObjectEvacuationStrategy<POINTER_OBJECT>:: 2132 Visit); 2133 2134 table_.Register(kVisitJSRegExp, 2135 &ObjectEvacuationStrategy<POINTER_OBJECT>:: 2136 Visit); 2137 2138 if (marks_handling == IGNORE_MARKS) { 2139 table_.Register(kVisitJSFunction, 2140 &ObjectEvacuationStrategy<POINTER_OBJECT>:: 2141 template VisitSpecialized<JSFunction::kSize>); 2142 } else { 2143 table_.Register(kVisitJSFunction, &EvacuateJSFunction); 2144 } 2145 2146 table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>, 2147 kVisitDataObject, 2148 kVisitDataObjectGeneric>(); 2149 2150 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, 2151 kVisitJSObject, 2152 kVisitJSObjectGeneric>(); 2153 2154 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, 2155 kVisitStruct, 2156 kVisitStructGeneric>(); 2157 } 2158 2159 static VisitorDispatchTable<ScavengingCallback>* GetTable() { 2160 return &table_; 2161 } 2162 2163 private: 2164 enum ObjectContents { DATA_OBJECT, POINTER_OBJECT }; 2165 2166 static void RecordCopiedObject(Heap* heap, HeapObject* obj) { 2167 bool should_record = false; 2168 #ifdef DEBUG 2169 should_record = FLAG_heap_stats; 2170 #endif 2171 should_record = should_record || FLAG_log_gc; 2172 if (should_record) { 2173 if (heap->new_space()->Contains(obj)) { 2174 heap->new_space()->RecordAllocation(obj); 2175 } else { 2176 heap->new_space()->RecordPromotion(obj); 2177 } 2178 } 2179 } 2180 2181 // Helper function used by CopyObject to copy a source object to an 2182 // allocated target object and update the forwarding pointer in the source 2183 // object. Returns the target object. 2184 INLINE(static void MigrateObject(Heap* heap, 2185 HeapObject* source, 2186 HeapObject* target, 2187 int size)) { 2188 // Copy the content of source to target. 2189 heap->CopyBlock(target->address(), source->address(), size); 2190 2191 // Set the forwarding address. 2192 source->set_map_word(MapWord::FromForwardingAddress(target)); 2193 2194 if (logging_and_profiling_mode == LOGGING_AND_PROFILING_ENABLED) { 2195 // Update NewSpace stats if necessary. 2196 RecordCopiedObject(heap, target); 2197 Isolate* isolate = heap->isolate(); 2198 HeapProfiler* heap_profiler = isolate->heap_profiler(); 2199 if (heap_profiler->is_tracking_object_moves()) { 2200 heap_profiler->ObjectMoveEvent(source->address(), target->address(), 2201 size); 2202 } 2203 if (isolate->logger()->is_logging_code_events() || 2204 isolate->cpu_profiler()->is_profiling()) { 2205 if (target->IsSharedFunctionInfo()) { 2206 PROFILE(isolate, SharedFunctionInfoMoveEvent( 2207 source->address(), target->address())); 2208 } 2209 } 2210 } 2211 2212 if (marks_handling == TRANSFER_MARKS) { 2213 if (Marking::TransferColor(source, target)) { 2214 MemoryChunk::IncrementLiveBytesFromGC(target->address(), size); 2215 } 2216 } 2217 } 2218 2219 2220 template<ObjectContents object_contents, int alignment> 2221 static inline void EvacuateObject(Map* map, 2222 HeapObject** slot, 2223 HeapObject* object, 2224 int object_size) { 2225 SLOW_ASSERT(object_size <= Page::kMaxNonCodeHeapObjectSize); 2226 SLOW_ASSERT(object->Size() == object_size); 2227 2228 int allocation_size = object_size; 2229 if (alignment != kObjectAlignment) { 2230 ASSERT(alignment == kDoubleAlignment); 2231 allocation_size += kPointerSize; 2232 } 2233 2234 Heap* heap = map->GetHeap(); 2235 if (heap->ShouldBePromoted(object->address(), object_size)) { 2236 MaybeObject* maybe_result; 2237 2238 if (object_contents == DATA_OBJECT) { 2239 ASSERT(heap->AllowedToBeMigrated(object, OLD_DATA_SPACE)); 2240 maybe_result = heap->old_data_space()->AllocateRaw(allocation_size); 2241 } else { 2242 ASSERT(heap->AllowedToBeMigrated(object, OLD_POINTER_SPACE)); 2243 maybe_result = heap->old_pointer_space()->AllocateRaw(allocation_size); 2244 } 2245 2246 Object* result = NULL; // Initialization to please compiler. 2247 if (maybe_result->ToObject(&result)) { 2248 HeapObject* target = HeapObject::cast(result); 2249 2250 if (alignment != kObjectAlignment) { 2251 target = EnsureDoubleAligned(heap, target, allocation_size); 2252 } 2253 2254 // Order is important: slot might be inside of the target if target 2255 // was allocated over a dead object and slot comes from the store 2256 // buffer. 2257 *slot = target; 2258 MigrateObject(heap, object, target, object_size); 2259 2260 if (object_contents == POINTER_OBJECT) { 2261 if (map->instance_type() == JS_FUNCTION_TYPE) { 2262 heap->promotion_queue()->insert( 2263 target, JSFunction::kNonWeakFieldsEndOffset); 2264 } else { 2265 heap->promotion_queue()->insert(target, object_size); 2266 } 2267 } 2268 2269 heap->tracer()->increment_promoted_objects_size(object_size); 2270 return; 2271 } 2272 } 2273 ASSERT(heap->AllowedToBeMigrated(object, NEW_SPACE)); 2274 MaybeObject* allocation = heap->new_space()->AllocateRaw(allocation_size); 2275 heap->promotion_queue()->SetNewLimit(heap->new_space()->top()); 2276 Object* result = allocation->ToObjectUnchecked(); 2277 HeapObject* target = HeapObject::cast(result); 2278 2279 if (alignment != kObjectAlignment) { 2280 target = EnsureDoubleAligned(heap, target, allocation_size); 2281 } 2282 2283 // Order is important: slot might be inside of the target if target 2284 // was allocated over a dead object and slot comes from the store 2285 // buffer. 2286 *slot = target; 2287 MigrateObject(heap, object, target, object_size); 2288 return; 2289 } 2290 2291 2292 static inline void EvacuateJSFunction(Map* map, 2293 HeapObject** slot, 2294 HeapObject* object) { 2295 ObjectEvacuationStrategy<POINTER_OBJECT>:: 2296 template VisitSpecialized<JSFunction::kSize>(map, slot, object); 2297 2298 HeapObject* target = *slot; 2299 MarkBit mark_bit = Marking::MarkBitFrom(target); 2300 if (Marking::IsBlack(mark_bit)) { 2301 // This object is black and it might not be rescanned by marker. 2302 // We should explicitly record code entry slot for compaction because 2303 // promotion queue processing (IterateAndMarkPointersToFromSpace) will 2304 // miss it as it is not HeapObject-tagged. 2305 Address code_entry_slot = 2306 target->address() + JSFunction::kCodeEntryOffset; 2307 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot)); 2308 map->GetHeap()->mark_compact_collector()-> 2309 RecordCodeEntrySlot(code_entry_slot, code); 2310 } 2311 } 2312 2313 2314 static inline void EvacuateFixedArray(Map* map, 2315 HeapObject** slot, 2316 HeapObject* object) { 2317 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object); 2318 EvacuateObject<POINTER_OBJECT, kObjectAlignment>( 2319 map, slot, object, object_size); 2320 } 2321 2322 2323 static inline void EvacuateFixedDoubleArray(Map* map, 2324 HeapObject** slot, 2325 HeapObject* object) { 2326 int length = reinterpret_cast<FixedDoubleArray*>(object)->length(); 2327 int object_size = FixedDoubleArray::SizeFor(length); 2328 EvacuateObject<DATA_OBJECT, kDoubleAlignment>( 2329 map, slot, object, object_size); 2330 } 2331 2332 2333 static inline void EvacuateByteArray(Map* map, 2334 HeapObject** slot, 2335 HeapObject* object) { 2336 int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize(); 2337 EvacuateObject<DATA_OBJECT, kObjectAlignment>( 2338 map, slot, object, object_size); 2339 } 2340 2341 2342 static inline void EvacuateSeqOneByteString(Map* map, 2343 HeapObject** slot, 2344 HeapObject* object) { 2345 int object_size = SeqOneByteString::cast(object)-> 2346 SeqOneByteStringSize(map->instance_type()); 2347 EvacuateObject<DATA_OBJECT, kObjectAlignment>( 2348 map, slot, object, object_size); 2349 } 2350 2351 2352 static inline void EvacuateSeqTwoByteString(Map* map, 2353 HeapObject** slot, 2354 HeapObject* object) { 2355 int object_size = SeqTwoByteString::cast(object)-> 2356 SeqTwoByteStringSize(map->instance_type()); 2357 EvacuateObject<DATA_OBJECT, kObjectAlignment>( 2358 map, slot, object, object_size); 2359 } 2360 2361 2362 static inline bool IsShortcutCandidate(int type) { 2363 return ((type & kShortcutTypeMask) == kShortcutTypeTag); 2364 } 2365 2366 static inline void EvacuateShortcutCandidate(Map* map, 2367 HeapObject** slot, 2368 HeapObject* object) { 2369 ASSERT(IsShortcutCandidate(map->instance_type())); 2370 2371 Heap* heap = map->GetHeap(); 2372 2373 if (marks_handling == IGNORE_MARKS && 2374 ConsString::cast(object)->unchecked_second() == 2375 heap->empty_string()) { 2376 HeapObject* first = 2377 HeapObject::cast(ConsString::cast(object)->unchecked_first()); 2378 2379 *slot = first; 2380 2381 if (!heap->InNewSpace(first)) { 2382 object->set_map_word(MapWord::FromForwardingAddress(first)); 2383 return; 2384 } 2385 2386 MapWord first_word = first->map_word(); 2387 if (first_word.IsForwardingAddress()) { 2388 HeapObject* target = first_word.ToForwardingAddress(); 2389 2390 *slot = target; 2391 object->set_map_word(MapWord::FromForwardingAddress(target)); 2392 return; 2393 } 2394 2395 heap->DoScavengeObject(first->map(), slot, first); 2396 object->set_map_word(MapWord::FromForwardingAddress(*slot)); 2397 return; 2398 } 2399 2400 int object_size = ConsString::kSize; 2401 EvacuateObject<POINTER_OBJECT, kObjectAlignment>( 2402 map, slot, object, object_size); 2403 } 2404 2405 template<ObjectContents object_contents> 2406 class ObjectEvacuationStrategy { 2407 public: 2408 template<int object_size> 2409 static inline void VisitSpecialized(Map* map, 2410 HeapObject** slot, 2411 HeapObject* object) { 2412 EvacuateObject<object_contents, kObjectAlignment>( 2413 map, slot, object, object_size); 2414 } 2415 2416 static inline void Visit(Map* map, 2417 HeapObject** slot, 2418 HeapObject* object) { 2419 int object_size = map->instance_size(); 2420 EvacuateObject<object_contents, kObjectAlignment>( 2421 map, slot, object, object_size); 2422 } 2423 }; 2424 2425 static VisitorDispatchTable<ScavengingCallback> table_; 2426 }; 2427 2428 2429 template<MarksHandling marks_handling, 2430 LoggingAndProfiling logging_and_profiling_mode> 2431 VisitorDispatchTable<ScavengingCallback> 2432 ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_; 2433 2434 2435 static void InitializeScavengingVisitorsTables() { 2436 ScavengingVisitor<TRANSFER_MARKS, 2437 LOGGING_AND_PROFILING_DISABLED>::Initialize(); 2438 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize(); 2439 ScavengingVisitor<TRANSFER_MARKS, 2440 LOGGING_AND_PROFILING_ENABLED>::Initialize(); 2441 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize(); 2442 } 2443 2444 2445 void Heap::SelectScavengingVisitorsTable() { 2446 bool logging_and_profiling = 2447 isolate()->logger()->is_logging() || 2448 isolate()->cpu_profiler()->is_profiling() || 2449 (isolate()->heap_profiler() != NULL && 2450 isolate()->heap_profiler()->is_tracking_object_moves()); 2451 2452 if (!incremental_marking()->IsMarking()) { 2453 if (!logging_and_profiling) { 2454 scavenging_visitors_table_.CopyFrom( 2455 ScavengingVisitor<IGNORE_MARKS, 2456 LOGGING_AND_PROFILING_DISABLED>::GetTable()); 2457 } else { 2458 scavenging_visitors_table_.CopyFrom( 2459 ScavengingVisitor<IGNORE_MARKS, 2460 LOGGING_AND_PROFILING_ENABLED>::GetTable()); 2461 } 2462 } else { 2463 if (!logging_and_profiling) { 2464 scavenging_visitors_table_.CopyFrom( 2465 ScavengingVisitor<TRANSFER_MARKS, 2466 LOGGING_AND_PROFILING_DISABLED>::GetTable()); 2467 } else { 2468 scavenging_visitors_table_.CopyFrom( 2469 ScavengingVisitor<TRANSFER_MARKS, 2470 LOGGING_AND_PROFILING_ENABLED>::GetTable()); 2471 } 2472 2473 if (incremental_marking()->IsCompacting()) { 2474 // When compacting forbid short-circuiting of cons-strings. 2475 // Scavenging code relies on the fact that new space object 2476 // can't be evacuated into evacuation candidate but 2477 // short-circuiting violates this assumption. 2478 scavenging_visitors_table_.Register( 2479 StaticVisitorBase::kVisitShortcutCandidate, 2480 scavenging_visitors_table_.GetVisitorById( 2481 StaticVisitorBase::kVisitConsString)); 2482 } 2483 } 2484 } 2485 2486 2487 void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { 2488 SLOW_ASSERT(object->GetIsolate()->heap()->InFromSpace(object)); 2489 MapWord first_word = object->map_word(); 2490 SLOW_ASSERT(!first_word.IsForwardingAddress()); 2491 Map* map = first_word.ToMap(); 2492 map->GetHeap()->DoScavengeObject(map, p, object); 2493 } 2494 2495 2496 MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, 2497 int instance_size) { 2498 Object* result; 2499 MaybeObject* maybe_result = AllocateRaw(Map::kSize, MAP_SPACE, MAP_SPACE); 2500 if (!maybe_result->ToObject(&result)) return maybe_result; 2501 2502 // Map::cast cannot be used due to uninitialized map field. 2503 reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map()); 2504 reinterpret_cast<Map*>(result)->set_instance_type(instance_type); 2505 reinterpret_cast<Map*>(result)->set_instance_size(instance_size); 2506 reinterpret_cast<Map*>(result)->set_visitor_id( 2507 StaticVisitorBase::GetVisitorId(instance_type, instance_size)); 2508 reinterpret_cast<Map*>(result)->set_inobject_properties(0); 2509 reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0); 2510 reinterpret_cast<Map*>(result)->set_unused_property_fields(0); 2511 reinterpret_cast<Map*>(result)->set_bit_field(0); 2512 reinterpret_cast<Map*>(result)->set_bit_field2(0); 2513 int bit_field3 = Map::EnumLengthBits::encode(kInvalidEnumCacheSentinel) | 2514 Map::OwnsDescriptors::encode(true); 2515 reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3); 2516 return result; 2517 } 2518 2519 2520 MaybeObject* Heap::AllocateMap(InstanceType instance_type, 2521 int instance_size, 2522 ElementsKind elements_kind) { 2523 Object* result; 2524 MaybeObject* maybe_result = AllocateRaw(Map::kSize, MAP_SPACE, MAP_SPACE); 2525 if (!maybe_result->To(&result)) return maybe_result; 2526 2527 Map* map = reinterpret_cast<Map*>(result); 2528 map->set_map_no_write_barrier(meta_map()); 2529 map->set_instance_type(instance_type); 2530 map->set_visitor_id( 2531 StaticVisitorBase::GetVisitorId(instance_type, instance_size)); 2532 map->set_prototype(null_value(), SKIP_WRITE_BARRIER); 2533 map->set_constructor(null_value(), SKIP_WRITE_BARRIER); 2534 map->set_instance_size(instance_size); 2535 map->set_inobject_properties(0); 2536 map->set_pre_allocated_property_fields(0); 2537 map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER); 2538 map->set_dependent_code(DependentCode::cast(empty_fixed_array()), 2539 SKIP_WRITE_BARRIER); 2540 map->init_back_pointer(undefined_value()); 2541 map->set_unused_property_fields(0); 2542 map->set_instance_descriptors(empty_descriptor_array()); 2543 map->set_bit_field(0); 2544 map->set_bit_field2(1 << Map::kIsExtensible); 2545 int bit_field3 = Map::EnumLengthBits::encode(kInvalidEnumCacheSentinel) | 2546 Map::OwnsDescriptors::encode(true); 2547 map->set_bit_field3(bit_field3); 2548 map->set_elements_kind(elements_kind); 2549 2550 return map; 2551 } 2552 2553 2554 MaybeObject* Heap::AllocateCodeCache() { 2555 CodeCache* code_cache; 2556 { MaybeObject* maybe_code_cache = AllocateStruct(CODE_CACHE_TYPE); 2557 if (!maybe_code_cache->To(&code_cache)) return maybe_code_cache; 2558 } 2559 code_cache->set_default_cache(empty_fixed_array(), SKIP_WRITE_BARRIER); 2560 code_cache->set_normal_type_cache(undefined_value(), SKIP_WRITE_BARRIER); 2561 return code_cache; 2562 } 2563 2564 2565 MaybeObject* Heap::AllocatePolymorphicCodeCache() { 2566 return AllocateStruct(POLYMORPHIC_CODE_CACHE_TYPE); 2567 } 2568 2569 2570 MaybeObject* Heap::AllocateAccessorPair() { 2571 AccessorPair* accessors; 2572 { MaybeObject* maybe_accessors = AllocateStruct(ACCESSOR_PAIR_TYPE); 2573 if (!maybe_accessors->To(&accessors)) return maybe_accessors; 2574 } 2575 accessors->set_getter(the_hole_value(), SKIP_WRITE_BARRIER); 2576 accessors->set_setter(the_hole_value(), SKIP_WRITE_BARRIER); 2577 accessors->set_access_flags(Smi::FromInt(0), SKIP_WRITE_BARRIER); 2578 return accessors; 2579 } 2580 2581 2582 MaybeObject* Heap::AllocateTypeFeedbackInfo() { 2583 TypeFeedbackInfo* info; 2584 { MaybeObject* maybe_info = AllocateStruct(TYPE_FEEDBACK_INFO_TYPE); 2585 if (!maybe_info->To(&info)) return maybe_info; 2586 } 2587 info->initialize_storage(); 2588 info->set_type_feedback_cells(TypeFeedbackCells::cast(empty_fixed_array()), 2589 SKIP_WRITE_BARRIER); 2590 return info; 2591 } 2592 2593 2594 MaybeObject* Heap::AllocateAliasedArgumentsEntry(int aliased_context_slot) { 2595 AliasedArgumentsEntry* entry; 2596 { MaybeObject* maybe_entry = AllocateStruct(ALIASED_ARGUMENTS_ENTRY_TYPE); 2597 if (!maybe_entry->To(&entry)) return maybe_entry; 2598 } 2599 entry->set_aliased_context_slot(aliased_context_slot); 2600 return entry; 2601 } 2602 2603 2604 const Heap::StringTypeTable Heap::string_type_table[] = { 2605 #define STRING_TYPE_ELEMENT(type, size, name, camel_name) \ 2606 {type, size, k##camel_name##MapRootIndex}, 2607 STRING_TYPE_LIST(STRING_TYPE_ELEMENT) 2608 #undef STRING_TYPE_ELEMENT 2609 }; 2610 2611 2612 const Heap::ConstantStringTable Heap::constant_string_table[] = { 2613 #define CONSTANT_STRING_ELEMENT(name, contents) \ 2614 {contents, k##name##RootIndex}, 2615 INTERNALIZED_STRING_LIST(CONSTANT_STRING_ELEMENT) 2616 #undef CONSTANT_STRING_ELEMENT 2617 }; 2618 2619 2620 const Heap::StructTable Heap::struct_table[] = { 2621 #define STRUCT_TABLE_ELEMENT(NAME, Name, name) \ 2622 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex }, 2623 STRUCT_LIST(STRUCT_TABLE_ELEMENT) 2624 #undef STRUCT_TABLE_ELEMENT 2625 }; 2626 2627 2628 bool Heap::CreateInitialMaps() { 2629 Object* obj; 2630 { MaybeObject* maybe_obj = AllocatePartialMap(MAP_TYPE, Map::kSize); 2631 if (!maybe_obj->ToObject(&obj)) return false; 2632 } 2633 // Map::cast cannot be used due to uninitialized map field. 2634 Map* new_meta_map = reinterpret_cast<Map*>(obj); 2635 set_meta_map(new_meta_map); 2636 new_meta_map->set_map(new_meta_map); 2637 2638 { MaybeObject* maybe_obj = 2639 AllocatePartialMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); 2640 if (!maybe_obj->ToObject(&obj)) return false; 2641 } 2642 set_fixed_array_map(Map::cast(obj)); 2643 2644 { MaybeObject* maybe_obj = AllocatePartialMap(ODDBALL_TYPE, Oddball::kSize); 2645 if (!maybe_obj->ToObject(&obj)) return false; 2646 } 2647 set_oddball_map(Map::cast(obj)); 2648 2649 // Allocate the empty array. 2650 { MaybeObject* maybe_obj = AllocateEmptyFixedArray(); 2651 if (!maybe_obj->ToObject(&obj)) return false; 2652 } 2653 set_empty_fixed_array(FixedArray::cast(obj)); 2654 2655 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE); 2656 if (!maybe_obj->ToObject(&obj)) return false; 2657 } 2658 set_null_value(Oddball::cast(obj)); 2659 Oddball::cast(obj)->set_kind(Oddball::kNull); 2660 2661 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE); 2662 if (!maybe_obj->ToObject(&obj)) return false; 2663 } 2664 set_undefined_value(Oddball::cast(obj)); 2665 Oddball::cast(obj)->set_kind(Oddball::kUndefined); 2666 ASSERT(!InNewSpace(undefined_value())); 2667 2668 // Allocate the empty descriptor array. 2669 { MaybeObject* maybe_obj = AllocateEmptyFixedArray(); 2670 if (!maybe_obj->ToObject(&obj)) return false; 2671 } 2672 set_empty_descriptor_array(DescriptorArray::cast(obj)); 2673 2674 // Fix the instance_descriptors for the existing maps. 2675 meta_map()->set_code_cache(empty_fixed_array()); 2676 meta_map()->set_dependent_code(DependentCode::cast(empty_fixed_array())); 2677 meta_map()->init_back_pointer(undefined_value()); 2678 meta_map()->set_instance_descriptors(empty_descriptor_array()); 2679 2680 fixed_array_map()->set_code_cache(empty_fixed_array()); 2681 fixed_array_map()->set_dependent_code( 2682 DependentCode::cast(empty_fixed_array())); 2683 fixed_array_map()->init_back_pointer(undefined_value()); 2684 fixed_array_map()->set_instance_descriptors(empty_descriptor_array()); 2685 2686 oddball_map()->set_code_cache(empty_fixed_array()); 2687 oddball_map()->set_dependent_code(DependentCode::cast(empty_fixed_array())); 2688 oddball_map()->init_back_pointer(undefined_value()); 2689 oddball_map()->set_instance_descriptors(empty_descriptor_array()); 2690 2691 // Fix prototype object for existing maps. 2692 meta_map()->set_prototype(null_value()); 2693 meta_map()->set_constructor(null_value()); 2694 2695 fixed_array_map()->set_prototype(null_value()); 2696 fixed_array_map()->set_constructor(null_value()); 2697 2698 oddball_map()->set_prototype(null_value()); 2699 oddball_map()->set_constructor(null_value()); 2700 2701 { MaybeObject* maybe_obj = 2702 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); 2703 if (!maybe_obj->ToObject(&obj)) return false; 2704 } 2705 set_fixed_cow_array_map(Map::cast(obj)); 2706 ASSERT(fixed_array_map() != fixed_cow_array_map()); 2707 2708 { MaybeObject* maybe_obj = 2709 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); 2710 if (!maybe_obj->ToObject(&obj)) return false; 2711 } 2712 set_scope_info_map(Map::cast(obj)); 2713 2714 { MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize); 2715 if (!maybe_obj->ToObject(&obj)) return false; 2716 } 2717 set_heap_number_map(Map::cast(obj)); 2718 2719 { MaybeObject* maybe_obj = AllocateMap(SYMBOL_TYPE, Symbol::kSize); 2720 if (!maybe_obj->ToObject(&obj)) return false; 2721 } 2722 set_symbol_map(Map::cast(obj)); 2723 2724 { MaybeObject* maybe_obj = AllocateMap(FOREIGN_TYPE, Foreign::kSize); 2725 if (!maybe_obj->ToObject(&obj)) return false; 2726 } 2727 set_foreign_map(Map::cast(obj)); 2728 2729 for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) { 2730 const StringTypeTable& entry = string_type_table[i]; 2731 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size); 2732 if (!maybe_obj->ToObject(&obj)) return false; 2733 } 2734 roots_[entry.index] = Map::cast(obj); 2735 } 2736 2737 { MaybeObject* maybe_obj = AllocateMap(STRING_TYPE, kVariableSizeSentinel); 2738 if (!maybe_obj->ToObject(&obj)) return false; 2739 } 2740 set_undetectable_string_map(Map::cast(obj)); 2741 Map::cast(obj)->set_is_undetectable(); 2742 2743 { MaybeObject* maybe_obj = 2744 AllocateMap(ASCII_STRING_TYPE, kVariableSizeSentinel); 2745 if (!maybe_obj->ToObject(&obj)) return false; 2746 } 2747 set_undetectable_ascii_string_map(Map::cast(obj)); 2748 Map::cast(obj)->set_is_undetectable(); 2749 2750 { MaybeObject* maybe_obj = 2751 AllocateMap(FIXED_DOUBLE_ARRAY_TYPE, kVariableSizeSentinel); 2752 if (!maybe_obj->ToObject(&obj)) return false; 2753 } 2754 set_fixed_double_array_map(Map::cast(obj)); 2755 2756 { MaybeObject* maybe_obj = 2757 AllocateMap(CONSTANT_POOL_ARRAY_TYPE, kVariableSizeSentinel); 2758 if (!maybe_obj->ToObject(&obj)) return false; 2759 } 2760 set_constant_pool_array_map(Map::cast(obj)); 2761 2762 { MaybeObject* maybe_obj = 2763 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel); 2764 if (!maybe_obj->ToObject(&obj)) return false; 2765 } 2766 set_byte_array_map(Map::cast(obj)); 2767 2768 { MaybeObject* maybe_obj = 2769 AllocateMap(FREE_SPACE_TYPE, kVariableSizeSentinel); 2770 if (!maybe_obj->ToObject(&obj)) return false; 2771 } 2772 set_free_space_map(Map::cast(obj)); 2773 2774 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED); 2775 if (!maybe_obj->ToObject(&obj)) return false; 2776 } 2777 set_empty_byte_array(ByteArray::cast(obj)); 2778 2779 { MaybeObject* maybe_obj = 2780 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize); 2781 if (!maybe_obj->ToObject(&obj)) return false; 2782 } 2783 set_external_pixel_array_map(Map::cast(obj)); 2784 2785 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_BYTE_ARRAY_TYPE, 2786 ExternalArray::kAlignedSize); 2787 if (!maybe_obj->ToObject(&obj)) return false; 2788 } 2789 set_external_byte_array_map(Map::cast(obj)); 2790 2791 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE, 2792 ExternalArray::kAlignedSize); 2793 if (!maybe_obj->ToObject(&obj)) return false; 2794 } 2795 set_external_unsigned_byte_array_map(Map::cast(obj)); 2796 2797 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_SHORT_ARRAY_TYPE, 2798 ExternalArray::kAlignedSize); 2799 if (!maybe_obj->ToObject(&obj)) return false; 2800 } 2801 set_external_short_array_map(Map::cast(obj)); 2802 2803 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE, 2804 ExternalArray::kAlignedSize); 2805 if (!maybe_obj->ToObject(&obj)) return false; 2806 } 2807 set_external_unsigned_short_array_map(Map::cast(obj)); 2808 2809 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_INT_ARRAY_TYPE, 2810 ExternalArray::kAlignedSize); 2811 if (!maybe_obj->ToObject(&obj)) return false; 2812 } 2813 set_external_int_array_map(Map::cast(obj)); 2814 2815 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE, 2816 ExternalArray::kAlignedSize); 2817 if (!maybe_obj->ToObject(&obj)) return false; 2818 } 2819 set_external_unsigned_int_array_map(Map::cast(obj)); 2820 2821 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_FLOAT_ARRAY_TYPE, 2822 ExternalArray::kAlignedSize); 2823 if (!maybe_obj->ToObject(&obj)) return false; 2824 } 2825 set_external_float_array_map(Map::cast(obj)); 2826 2827 { MaybeObject* maybe_obj = 2828 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); 2829 if (!maybe_obj->ToObject(&obj)) return false; 2830 } 2831 set_non_strict_arguments_elements_map(Map::cast(obj)); 2832 2833 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_DOUBLE_ARRAY_TYPE, 2834 ExternalArray::kAlignedSize); 2835 if (!maybe_obj->ToObject(&obj)) return false; 2836 } 2837 set_external_double_array_map(Map::cast(obj)); 2838 2839 { MaybeObject* maybe_obj = AllocateEmptyExternalArray(kExternalByteArray); 2840 if (!maybe_obj->ToObject(&obj)) return false; 2841 } 2842 set_empty_external_byte_array(ExternalArray::cast(obj)); 2843 2844 { MaybeObject* maybe_obj = 2845 AllocateEmptyExternalArray(kExternalUnsignedByteArray); 2846 if (!maybe_obj->ToObject(&obj)) return false; 2847 } 2848 set_empty_external_unsigned_byte_array(ExternalArray::cast(obj)); 2849 2850 { MaybeObject* maybe_obj = AllocateEmptyExternalArray(kExternalShortArray); 2851 if (!maybe_obj->ToObject(&obj)) return false; 2852 } 2853 set_empty_external_short_array(ExternalArray::cast(obj)); 2854 2855 { MaybeObject* maybe_obj = AllocateEmptyExternalArray( 2856 kExternalUnsignedShortArray); 2857 if (!maybe_obj->ToObject(&obj)) return false; 2858 } 2859 set_empty_external_unsigned_short_array(ExternalArray::cast(obj)); 2860 2861 { MaybeObject* maybe_obj = AllocateEmptyExternalArray(kExternalIntArray); 2862 if (!maybe_obj->ToObject(&obj)) return false; 2863 } 2864 set_empty_external_int_array(ExternalArray::cast(obj)); 2865 2866 { MaybeObject* maybe_obj = 2867 AllocateEmptyExternalArray(kExternalUnsignedIntArray); 2868 if (!maybe_obj->ToObject(&obj)) return false; 2869 } 2870 set_empty_external_unsigned_int_array(ExternalArray::cast(obj)); 2871 2872 { MaybeObject* maybe_obj = AllocateEmptyExternalArray(kExternalFloatArray); 2873 if (!maybe_obj->ToObject(&obj)) return false; 2874 } 2875 set_empty_external_float_array(ExternalArray::cast(obj)); 2876 2877 { MaybeObject* maybe_obj = AllocateEmptyExternalArray(kExternalDoubleArray); 2878 if (!maybe_obj->ToObject(&obj)) return false; 2879 } 2880 set_empty_external_double_array(ExternalArray::cast(obj)); 2881 2882 { MaybeObject* maybe_obj = AllocateEmptyExternalArray(kExternalPixelArray); 2883 if (!maybe_obj->ToObject(&obj)) return false; 2884 } 2885 set_empty_external_pixel_array(ExternalArray::cast(obj)); 2886 2887 { MaybeObject* maybe_obj = AllocateMap(CODE_TYPE, kVariableSizeSentinel); 2888 if (!maybe_obj->ToObject(&obj)) return false; 2889 } 2890 set_code_map(Map::cast(obj)); 2891 2892 { MaybeObject* maybe_obj = AllocateMap(CELL_TYPE, Cell::kSize); 2893 if (!maybe_obj->ToObject(&obj)) return false; 2894 } 2895 set_cell_map(Map::cast(obj)); 2896 2897 { MaybeObject* maybe_obj = AllocateMap(PROPERTY_CELL_TYPE, 2898 PropertyCell::kSize); 2899 if (!maybe_obj->ToObject(&obj)) return false; 2900 } 2901 set_global_property_cell_map(Map::cast(obj)); 2902 2903 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, kPointerSize); 2904 if (!maybe_obj->ToObject(&obj)) return false; 2905 } 2906 set_one_pointer_filler_map(Map::cast(obj)); 2907 2908 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize); 2909 if (!maybe_obj->ToObject(&obj)) return false; 2910 } 2911 set_two_pointer_filler_map(Map::cast(obj)); 2912 2913 for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) { 2914 const StructTable& entry = struct_table[i]; 2915 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size); 2916 if (!maybe_obj->ToObject(&obj)) return false; 2917 } 2918 roots_[entry.index] = Map::cast(obj); 2919 } 2920 2921 { MaybeObject* maybe_obj = 2922 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); 2923 if (!maybe_obj->ToObject(&obj)) return false; 2924 } 2925 set_hash_table_map(Map::cast(obj)); 2926 2927 { MaybeObject* maybe_obj = 2928 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); 2929 if (!maybe_obj->ToObject(&obj)) return false; 2930 } 2931 set_function_context_map(Map::cast(obj)); 2932 2933 { MaybeObject* maybe_obj = 2934 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); 2935 if (!maybe_obj->ToObject(&obj)) return false; 2936 } 2937 set_catch_context_map(Map::cast(obj)); 2938 2939 { MaybeObject* maybe_obj = 2940 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); 2941 if (!maybe_obj->ToObject(&obj)) return false; 2942 } 2943 set_with_context_map(Map::cast(obj)); 2944 2945 { MaybeObject* maybe_obj = 2946 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); 2947 if (!maybe_obj->ToObject(&obj)) return false; 2948 } 2949 set_block_context_map(Map::cast(obj)); 2950 2951 { MaybeObject* maybe_obj = 2952 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); 2953 if (!maybe_obj->ToObject(&obj)) return false; 2954 } 2955 set_module_context_map(Map::cast(obj)); 2956 2957 { MaybeObject* maybe_obj = 2958 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); 2959 if (!maybe_obj->ToObject(&obj)) return false; 2960 } 2961 set_global_context_map(Map::cast(obj)); 2962 2963 { MaybeObject* maybe_obj = 2964 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); 2965 if (!maybe_obj->ToObject(&obj)) return false; 2966 } 2967 Map* native_context_map = Map::cast(obj); 2968 native_context_map->set_dictionary_map(true); 2969 native_context_map->set_visitor_id(StaticVisitorBase::kVisitNativeContext); 2970 set_native_context_map(native_context_map); 2971 2972 { MaybeObject* maybe_obj = AllocateMap(SHARED_FUNCTION_INFO_TYPE, 2973 SharedFunctionInfo::kAlignedSize); 2974 if (!maybe_obj->ToObject(&obj)) return false; 2975 } 2976 set_shared_function_info_map(Map::cast(obj)); 2977 2978 { MaybeObject* maybe_obj = AllocateMap(JS_MESSAGE_OBJECT_TYPE, 2979 JSMessageObject::kSize); 2980 if (!maybe_obj->ToObject(&obj)) return false; 2981 } 2982 set_message_object_map(Map::cast(obj)); 2983 2984 Map* external_map; 2985 { MaybeObject* maybe_obj = 2986 AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize); 2987 if (!maybe_obj->To(&external_map)) return false; 2988 } 2989 external_map->set_is_extensible(false); 2990 set_external_map(external_map); 2991 2992 ASSERT(!InNewSpace(empty_fixed_array())); 2993 return true; 2994 } 2995 2996 2997 MaybeObject* Heap::AllocateHeapNumber(double value, PretenureFlag pretenure) { 2998 // Statically ensure that it is safe to allocate heap numbers in paged 2999 // spaces. 3000 int size = HeapNumber::kSize; 3001 STATIC_ASSERT(HeapNumber::kSize <= Page::kNonCodeObjectAreaSize); 3002 AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); 3003 3004 Object* result; 3005 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE); 3006 if (!maybe_result->ToObject(&result)) return maybe_result; 3007 } 3008 3009 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map()); 3010 HeapNumber::cast(result)->set_value(value); 3011 return result; 3012 } 3013 3014 3015 MaybeObject* Heap::AllocateCell(Object* value) { 3016 int size = Cell::kSize; 3017 STATIC_ASSERT(Cell::kSize <= Page::kNonCodeObjectAreaSize); 3018 3019 Object* result; 3020 { MaybeObject* maybe_result = AllocateRaw(size, CELL_SPACE, CELL_SPACE); 3021 if (!maybe_result->ToObject(&result)) return maybe_result; 3022 } 3023 HeapObject::cast(result)->set_map_no_write_barrier(cell_map()); 3024 Cell::cast(result)->set_value(value); 3025 return result; 3026 } 3027 3028 3029 MaybeObject* Heap::AllocatePropertyCell() { 3030 int size = PropertyCell::kSize; 3031 STATIC_ASSERT(PropertyCell::kSize <= Page::kNonCodeObjectAreaSize); 3032 3033 Object* result; 3034 MaybeObject* maybe_result = 3035 AllocateRaw(size, PROPERTY_CELL_SPACE, PROPERTY_CELL_SPACE); 3036 if (!maybe_result->ToObject(&result)) return maybe_result; 3037 3038 HeapObject::cast(result)->set_map_no_write_barrier( 3039 global_property_cell_map()); 3040 PropertyCell* cell = PropertyCell::cast(result); 3041 cell->set_dependent_code(DependentCode::cast(empty_fixed_array()), 3042 SKIP_WRITE_BARRIER); 3043 cell->set_value(the_hole_value()); 3044 cell->set_type(Type::None()); 3045 return result; 3046 } 3047 3048 3049 MaybeObject* Heap::AllocateBox(Object* value, PretenureFlag pretenure) { 3050 Box* result; 3051 MaybeObject* maybe_result = AllocateStruct(BOX_TYPE); 3052 if (!maybe_result->To(&result)) return maybe_result; 3053 result->set_value(value); 3054 return result; 3055 } 3056 3057 3058 MaybeObject* Heap::AllocateAllocationSite() { 3059 AllocationSite* site; 3060 MaybeObject* maybe_result = Allocate(allocation_site_map(), 3061 OLD_POINTER_SPACE); 3062 if (!maybe_result->To(&site)) return maybe_result; 3063 site->Initialize(); 3064 3065 // Link the site 3066 site->set_weak_next(allocation_sites_list()); 3067 set_allocation_sites_list(site); 3068 return site; 3069 } 3070 3071 3072 MaybeObject* Heap::CreateOddball(const char* to_string, 3073 Object* to_number, 3074 byte kind) { 3075 Object* result; 3076 { MaybeObject* maybe_result = Allocate(oddball_map(), OLD_POINTER_SPACE); 3077 if (!maybe_result->ToObject(&result)) return maybe_result; 3078 } 3079 return Oddball::cast(result)->Initialize(this, to_string, to_number, kind); 3080 } 3081 3082 3083 bool Heap::CreateApiObjects() { 3084 Object* obj; 3085 3086 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); 3087 if (!maybe_obj->ToObject(&obj)) return false; 3088 } 3089 // Don't use Smi-only elements optimizations for objects with the neander 3090 // map. There are too many cases where element values are set directly with a 3091 // bottleneck to trap the Smi-only -> fast elements transition, and there 3092 // appears to be no benefit for optimize this case. 3093 Map* new_neander_map = Map::cast(obj); 3094 new_neander_map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND); 3095 set_neander_map(new_neander_map); 3096 3097 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map()); 3098 if (!maybe_obj->ToObject(&obj)) return false; 3099 } 3100 Object* elements; 3101 { MaybeObject* maybe_elements = AllocateFixedArray(2); 3102 if (!maybe_elements->ToObject(&elements)) return false; 3103 } 3104 FixedArray::cast(elements)->set(0, Smi::FromInt(0)); 3105 JSObject::cast(obj)->set_elements(FixedArray::cast(elements)); 3106 set_message_listeners(JSObject::cast(obj)); 3107 3108 return true; 3109 } 3110 3111 3112 void Heap::CreateJSEntryStub() { 3113 JSEntryStub stub; 3114 set_js_entry_code(*stub.GetCode(isolate())); 3115 } 3116 3117 3118 void Heap::CreateJSConstructEntryStub() { 3119 JSConstructEntryStub stub; 3120 set_js_construct_entry_code(*stub.GetCode(isolate())); 3121 } 3122 3123 3124 void Heap::CreateFixedStubs() { 3125 // Here we create roots for fixed stubs. They are needed at GC 3126 // for cooking and uncooking (check out frames.cc). 3127 // The eliminates the need for doing dictionary lookup in the 3128 // stub cache for these stubs. 3129 HandleScope scope(isolate()); 3130 // gcc-4.4 has problem generating correct code of following snippet: 3131 // { JSEntryStub stub; 3132 // js_entry_code_ = *stub.GetCode(); 3133 // } 3134 // { JSConstructEntryStub stub; 3135 // js_construct_entry_code_ = *stub.GetCode(); 3136 // } 3137 // To workaround the problem, make separate functions without inlining. 3138 Heap::CreateJSEntryStub(); 3139 Heap::CreateJSConstructEntryStub(); 3140 3141 // Create stubs that should be there, so we don't unexpectedly have to 3142 // create them if we need them during the creation of another stub. 3143 // Stub creation mixes raw pointers and handles in an unsafe manner so 3144 // we cannot create stubs while we are creating stubs. 3145 CodeStub::GenerateStubsAheadOfTime(isolate()); 3146 } 3147 3148 3149 void Heap::CreateStubsRequiringBuiltins() { 3150 HandleScope scope(isolate()); 3151 CodeStub::GenerateStubsRequiringBuiltinsAheadOfTime(isolate()); 3152 } 3153 3154 3155 bool Heap::CreateInitialObjects() { 3156 Object* obj; 3157 3158 // The -0 value must be set before NumberFromDouble works. 3159 { MaybeObject* maybe_obj = AllocateHeapNumber(-0.0, TENURED); 3160 if (!maybe_obj->ToObject(&obj)) return false; 3161 } 3162 set_minus_zero_value(HeapNumber::cast(obj)); 3163 ASSERT(std::signbit(minus_zero_value()->Number()) != 0); 3164 3165 { MaybeObject* maybe_obj = AllocateHeapNumber(OS::nan_value(), TENURED); 3166 if (!maybe_obj->ToObject(&obj)) return false; 3167 } 3168 set_nan_value(HeapNumber::cast(obj)); 3169 3170 { MaybeObject* maybe_obj = AllocateHeapNumber(V8_INFINITY, TENURED); 3171 if (!maybe_obj->ToObject(&obj)) return false; 3172 } 3173 set_infinity_value(HeapNumber::cast(obj)); 3174 3175 // The hole has not been created yet, but we want to put something 3176 // predictable in the gaps in the string table, so lets make that Smi zero. 3177 set_the_hole_value(reinterpret_cast<Oddball*>(Smi::FromInt(0))); 3178 3179 // Allocate initial string table. 3180 { MaybeObject* maybe_obj = 3181 StringTable::Allocate(this, kInitialStringTableSize); 3182 if (!maybe_obj->ToObject(&obj)) return false; 3183 } 3184 // Don't use set_string_table() due to asserts. 3185 roots_[kStringTableRootIndex] = obj; 3186 3187 // Finish initializing oddballs after creating the string table. 3188 { MaybeObject* maybe_obj = 3189 undefined_value()->Initialize(this, 3190 "undefined", 3191 nan_value(), 3192 Oddball::kUndefined); 3193 if (!maybe_obj->ToObject(&obj)) return false; 3194 } 3195 3196 // Initialize the null_value. 3197 { MaybeObject* maybe_obj = null_value()->Initialize( 3198 this, "null", Smi::FromInt(0), Oddball::kNull); 3199 if (!maybe_obj->ToObject(&obj)) return false; 3200 } 3201 3202 { MaybeObject* maybe_obj = CreateOddball("true", 3203 Smi::FromInt(1), 3204 Oddball::kTrue); 3205 if (!maybe_obj->ToObject(&obj)) return false; 3206 } 3207 set_true_value(Oddball::cast(obj)); 3208 3209 { MaybeObject* maybe_obj = CreateOddball("false", 3210 Smi::FromInt(0), 3211 Oddball::kFalse); 3212 if (!maybe_obj->ToObject(&obj)) return false; 3213 } 3214 set_false_value(Oddball::cast(obj)); 3215 3216 { MaybeObject* maybe_obj = CreateOddball("hole", 3217 Smi::FromInt(-1), 3218 Oddball::kTheHole); 3219 if (!maybe_obj->ToObject(&obj)) return false; 3220 } 3221 set_the_hole_value(Oddball::cast(obj)); 3222 3223 { MaybeObject* maybe_obj = CreateOddball("uninitialized", 3224 Smi::FromInt(-1), 3225 Oddball::kUninitialized); 3226 if (!maybe_obj->ToObject(&obj)) return false; 3227 } 3228 set_uninitialized_value(Oddball::cast(obj)); 3229 3230 { MaybeObject* maybe_obj = CreateOddball("arguments_marker", 3231 Smi::FromInt(-4), 3232 Oddball::kArgumentMarker); 3233 if (!maybe_obj->ToObject(&obj)) return false; 3234 } 3235 set_arguments_marker(Oddball::cast(obj)); 3236 3237 { MaybeObject* maybe_obj = CreateOddball("no_interceptor_result_sentinel", 3238 Smi::FromInt(-2), 3239 Oddball::kOther); 3240 if (!maybe_obj->ToObject(&obj)) return false; 3241 } 3242 set_no_interceptor_result_sentinel(obj); 3243 3244 { MaybeObject* maybe_obj = CreateOddball("termination_exception", 3245 Smi::FromInt(-3), 3246 Oddball::kOther); 3247 if (!maybe_obj->ToObject(&obj)) return false; 3248 } 3249 set_termination_exception(obj); 3250 3251 for (unsigned i = 0; i < ARRAY_SIZE(constant_string_table); i++) { 3252 { MaybeObject* maybe_obj = 3253 InternalizeUtf8String(constant_string_table[i].contents); 3254 if (!maybe_obj->ToObject(&obj)) return false; 3255 } 3256 roots_[constant_string_table[i].index] = String::cast(obj); 3257 } 3258 3259 // Allocate the hidden string which is used to identify the hidden properties 3260 // in JSObjects. The hash code has a special value so that it will not match 3261 // the empty string when searching for the property. It cannot be part of the 3262 // loop above because it needs to be allocated manually with the special 3263 // hash code in place. The hash code for the hidden_string is zero to ensure 3264 // that it will always be at the first entry in property descriptors. 3265 { MaybeObject* maybe_obj = AllocateOneByteInternalizedString( 3266 OneByteVector("", 0), String::kEmptyStringHash); 3267 if (!maybe_obj->ToObject(&obj)) return false; 3268 } 3269 hidden_string_ = String::cast(obj); 3270 3271 // Allocate the code_stubs dictionary. The initial size is set to avoid 3272 // expanding the dictionary during bootstrapping. 3273 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(this, 128); 3274 if (!maybe_obj->ToObject(&obj)) return false; 3275 } 3276 set_code_stubs(UnseededNumberDictionary::cast(obj)); 3277 3278 3279 // Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size 3280 // is set to avoid expanding the dictionary during bootstrapping. 3281 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(this, 64); 3282 if (!maybe_obj->ToObject(&obj)) return false; 3283 } 3284 set_non_monomorphic_cache(UnseededNumberDictionary::cast(obj)); 3285 3286 { MaybeObject* maybe_obj = AllocatePolymorphicCodeCache(); 3287 if (!maybe_obj->ToObject(&obj)) return false; 3288 } 3289 set_polymorphic_code_cache(PolymorphicCodeCache::cast(obj)); 3290 3291 set_instanceof_cache_function(Smi::FromInt(0)); 3292 set_instanceof_cache_map(Smi::FromInt(0)); 3293 set_instanceof_cache_answer(Smi::FromInt(0)); 3294 3295 CreateFixedStubs(); 3296 3297 // Allocate the dictionary of intrinsic function names. 3298 { MaybeObject* maybe_obj = 3299 NameDictionary::Allocate(this, Runtime::kNumFunctions); 3300 if (!maybe_obj->ToObject(&obj)) return false; 3301 } 3302 { MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(this, 3303 obj); 3304 if (!maybe_obj->ToObject(&obj)) return false; 3305 } 3306 set_intrinsic_function_names(NameDictionary::cast(obj)); 3307 3308 { MaybeObject* maybe_obj = AllocateInitialNumberStringCache(); 3309 if (!maybe_obj->ToObject(&obj)) return false; 3310 } 3311 set_number_string_cache(FixedArray::cast(obj)); 3312 3313 // Allocate cache for single character one byte strings. 3314 { MaybeObject* maybe_obj = 3315 AllocateFixedArray(String::kMaxOneByteCharCode + 1, TENURED); 3316 if (!maybe_obj->ToObject(&obj)) return false; 3317 } 3318 set_single_character_string_cache(FixedArray::cast(obj)); 3319 3320 // Allocate cache for string split. 3321 { MaybeObject* maybe_obj = AllocateFixedArray( 3322 RegExpResultsCache::kRegExpResultsCacheSize, TENURED); 3323 if (!maybe_obj->ToObject(&obj)) return false; 3324 } 3325 set_string_split_cache(FixedArray::cast(obj)); 3326 3327 { MaybeObject* maybe_obj = AllocateFixedArray( 3328 RegExpResultsCache::kRegExpResultsCacheSize, TENURED); 3329 if (!maybe_obj->ToObject(&obj)) return false; 3330 } 3331 set_regexp_multiple_cache(FixedArray::cast(obj)); 3332 3333 // Allocate cache for external strings pointing to native source code. 3334 { MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount()); 3335 if (!maybe_obj->ToObject(&obj)) return false; 3336 } 3337 set_natives_source_cache(FixedArray::cast(obj)); 3338 3339 // Allocate object to hold object observation state. 3340 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); 3341 if (!maybe_obj->ToObject(&obj)) return false; 3342 } 3343 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(Map::cast(obj)); 3344 if (!maybe_obj->ToObject(&obj)) return false; 3345 } 3346 set_observation_state(JSObject::cast(obj)); 3347 3348 { MaybeObject* maybe_obj = AllocateSymbol(); 3349 if (!maybe_obj->ToObject(&obj)) return false; 3350 } 3351 Symbol::cast(obj)->set_is_private(true); 3352 set_frozen_symbol(Symbol::cast(obj)); 3353 3354 { MaybeObject* maybe_obj = AllocateSymbol(); 3355 if (!maybe_obj->ToObject(&obj)) return false; 3356 } 3357 Symbol::cast(obj)->set_is_private(true); 3358 set_elements_transition_symbol(Symbol::cast(obj)); 3359 3360 { MaybeObject* maybe_obj = SeededNumberDictionary::Allocate(this, 0, TENURED); 3361 if (!maybe_obj->ToObject(&obj)) return false; 3362 } 3363 SeededNumberDictionary::cast(obj)->set_requires_slow_elements(); 3364 set_empty_slow_element_dictionary(SeededNumberDictionary::cast(obj)); 3365 3366 { MaybeObject* maybe_obj = AllocateSymbol(); 3367 if (!maybe_obj->ToObject(&obj)) return false; 3368 } 3369 Symbol::cast(obj)->set_is_private(true); 3370 set_observed_symbol(Symbol::cast(obj)); 3371 3372 // Handling of script id generation is in Factory::NewScript. 3373 set_last_script_id(Smi::FromInt(v8::Script::kNoScriptId)); 3374 3375 // Initialize keyed lookup cache. 3376 isolate_->keyed_lookup_cache()->Clear(); 3377 3378 // Initialize context slot cache. 3379 isolate_->context_slot_cache()->Clear(); 3380 3381 // Initialize descriptor cache. 3382 isolate_->descriptor_lookup_cache()->Clear(); 3383 3384 // Initialize compilation cache. 3385 isolate_->compilation_cache()->Clear(); 3386 3387 return true; 3388 } 3389 3390 3391 bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) { 3392 RootListIndex writable_roots[] = { 3393 kStoreBufferTopRootIndex, 3394 kStackLimitRootIndex, 3395 kNumberStringCacheRootIndex, 3396 kInstanceofCacheFunctionRootIndex, 3397 kInstanceofCacheMapRootIndex, 3398 kInstanceofCacheAnswerRootIndex, 3399 kCodeStubsRootIndex, 3400 kNonMonomorphicCacheRootIndex, 3401 kPolymorphicCodeCacheRootIndex, 3402 kLastScriptIdRootIndex, 3403 kEmptyScriptRootIndex, 3404 kRealStackLimitRootIndex, 3405 kArgumentsAdaptorDeoptPCOffsetRootIndex, 3406 kConstructStubDeoptPCOffsetRootIndex, 3407 kGetterStubDeoptPCOffsetRootIndex, 3408 kSetterStubDeoptPCOffsetRootIndex, 3409 kStringTableRootIndex, 3410 }; 3411 3412 for (unsigned int i = 0; i < ARRAY_SIZE(writable_roots); i++) { 3413 if (root_index == writable_roots[i]) 3414 return true; 3415 } 3416 return false; 3417 } 3418 3419 3420 bool Heap::RootCanBeTreatedAsConstant(RootListIndex root_index) { 3421 return !RootCanBeWrittenAfterInitialization(root_index) && 3422 !InNewSpace(roots_array_start()[root_index]); 3423 } 3424 3425 3426 Object* RegExpResultsCache::Lookup(Heap* heap, 3427 String* key_string, 3428 Object* key_pattern, 3429 ResultsCacheType type) { 3430 FixedArray* cache; 3431 if (!key_string->IsInternalizedString()) return Smi::FromInt(0); 3432 if (type == STRING_SPLIT_SUBSTRINGS) { 3433 ASSERT(key_pattern->IsString()); 3434 if (!key_pattern->IsInternalizedString()) return Smi::FromInt(0); 3435 cache = heap->string_split_cache(); 3436 } else { 3437 ASSERT(type == REGEXP_MULTIPLE_INDICES); 3438 ASSERT(key_pattern->IsFixedArray()); 3439 cache = heap->regexp_multiple_cache(); 3440 } 3441 3442 uint32_t hash = key_string->Hash(); 3443 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) & 3444 ~(kArrayEntriesPerCacheEntry - 1)); 3445 if (cache->get(index + kStringOffset) == key_string && 3446 cache->get(index + kPatternOffset) == key_pattern) { 3447 return cache->get(index + kArrayOffset); 3448 } 3449 index = 3450 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1)); 3451 if (cache->get(index + kStringOffset) == key_string && 3452 cache->get(index + kPatternOffset) == key_pattern) { 3453 return cache->get(index + kArrayOffset); 3454 } 3455 return Smi::FromInt(0); 3456 } 3457 3458 3459 void RegExpResultsCache::Enter(Heap* heap, 3460 String* key_string, 3461 Object* key_pattern, 3462 FixedArray* value_array, 3463 ResultsCacheType type) { 3464 FixedArray* cache; 3465 if (!key_string->IsInternalizedString()) return; 3466 if (type == STRING_SPLIT_SUBSTRINGS) { 3467 ASSERT(key_pattern->IsString()); 3468 if (!key_pattern->IsInternalizedString()) return; 3469 cache = heap->string_split_cache(); 3470 } else { 3471 ASSERT(type == REGEXP_MULTIPLE_INDICES); 3472 ASSERT(key_pattern->IsFixedArray()); 3473 cache = heap->regexp_multiple_cache(); 3474 } 3475 3476 uint32_t hash = key_string->Hash(); 3477 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) & 3478 ~(kArrayEntriesPerCacheEntry - 1)); 3479 if (cache->get(index + kStringOffset) == Smi::FromInt(0)) { 3480 cache->set(index + kStringOffset, key_string); 3481 cache->set(index + kPatternOffset, key_pattern); 3482 cache->set(index + kArrayOffset, value_array); 3483 } else { 3484 uint32_t index2 = 3485 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1)); 3486 if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) { 3487 cache->set(index2 + kStringOffset, key_string); 3488 cache->set(index2 + kPatternOffset, key_pattern); 3489 cache->set(index2 + kArrayOffset, value_array); 3490 } else { 3491 cache->set(index2 + kStringOffset, Smi::FromInt(0)); 3492 cache->set(index2 + kPatternOffset, Smi::FromInt(0)); 3493 cache->set(index2 + kArrayOffset, Smi::FromInt(0)); 3494 cache->set(index + kStringOffset, key_string); 3495 cache->set(index + kPatternOffset, key_pattern); 3496 cache->set(index + kArrayOffset, value_array); 3497 } 3498 } 3499 // If the array is a reasonably short list of substrings, convert it into a 3500 // list of internalized strings. 3501 if (type == STRING_SPLIT_SUBSTRINGS && value_array->length() < 100) { 3502 for (int i = 0; i < value_array->length(); i++) { 3503 String* str = String::cast(value_array->get(i)); 3504 Object* internalized_str; 3505 MaybeObject* maybe_string = heap->InternalizeString(str); 3506 if (maybe_string->ToObject(&internalized_str)) { 3507 value_array->set(i, internalized_str); 3508 } 3509 } 3510 } 3511 // Convert backing store to a copy-on-write array. 3512 value_array->set_map_no_write_barrier(heap->fixed_cow_array_map()); 3513 } 3514 3515 3516 void RegExpResultsCache::Clear(FixedArray* cache) { 3517 for (int i = 0; i < kRegExpResultsCacheSize; i++) { 3518 cache->set(i, Smi::FromInt(0)); 3519 } 3520 } 3521 3522 3523 MaybeObject* Heap::AllocateInitialNumberStringCache() { 3524 MaybeObject* maybe_obj = 3525 AllocateFixedArray(kInitialNumberStringCacheSize * 2, TENURED); 3526 return maybe_obj; 3527 } 3528 3529 3530 int Heap::FullSizeNumberStringCacheLength() { 3531 // Compute the size of the number string cache based on the max newspace size. 3532 // The number string cache has a minimum size based on twice the initial cache 3533 // size to ensure that it is bigger after being made 'full size'. 3534 int number_string_cache_size = max_semispace_size_ / 512; 3535 number_string_cache_size = Max(kInitialNumberStringCacheSize * 2, 3536 Min(0x4000, number_string_cache_size)); 3537 // There is a string and a number per entry so the length is twice the number 3538 // of entries. 3539 return number_string_cache_size * 2; 3540 } 3541 3542 3543 void Heap::AllocateFullSizeNumberStringCache() { 3544 // The idea is to have a small number string cache in the snapshot to keep 3545 // boot-time memory usage down. If we expand the number string cache already 3546 // while creating the snapshot then that didn't work out. 3547 ASSERT(!Serializer::enabled() || FLAG_extra_code != NULL); 3548 MaybeObject* maybe_obj = 3549 AllocateFixedArray(FullSizeNumberStringCacheLength(), TENURED); 3550 Object* new_cache; 3551 if (maybe_obj->ToObject(&new_cache)) { 3552 // We don't bother to repopulate the cache with entries from the old cache. 3553 // It will be repopulated soon enough with new strings. 3554 set_number_string_cache(FixedArray::cast(new_cache)); 3555 } 3556 // If allocation fails then we just return without doing anything. It is only 3557 // a cache, so best effort is OK here. 3558 } 3559 3560 3561 void Heap::FlushNumberStringCache() { 3562 // Flush the number to string cache. 3563 int len = number_string_cache()->length(); 3564 for (int i = 0; i < len; i++) { 3565 number_string_cache()->set_undefined(i); 3566 } 3567 } 3568 3569 3570 static inline int double_get_hash(double d) { 3571 DoubleRepresentation rep(d); 3572 return static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32); 3573 } 3574 3575 3576 static inline int smi_get_hash(Smi* smi) { 3577 return smi->value(); 3578 } 3579 3580 3581 Object* Heap::GetNumberStringCache(Object* number) { 3582 int hash; 3583 int mask = (number_string_cache()->length() >> 1) - 1; 3584 if (number->IsSmi()) { 3585 hash = smi_get_hash(Smi::cast(number)) & mask; 3586 } else { 3587 hash = double_get_hash(number->Number()) & mask; 3588 } 3589 Object* key = number_string_cache()->get(hash * 2); 3590 if (key == number) { 3591 return String::cast(number_string_cache()->get(hash * 2 + 1)); 3592 } else if (key->IsHeapNumber() && 3593 number->IsHeapNumber() && 3594 key->Number() == number->Number()) { 3595 return String::cast(number_string_cache()->get(hash * 2 + 1)); 3596 } 3597 return undefined_value(); 3598 } 3599 3600 3601 void Heap::SetNumberStringCache(Object* number, String* string) { 3602 int hash; 3603 int mask = (number_string_cache()->length() >> 1) - 1; 3604 if (number->IsSmi()) { 3605 hash = smi_get_hash(Smi::cast(number)) & mask; 3606 } else { 3607 hash = double_get_hash(number->Number()) & mask; 3608 } 3609 if (number_string_cache()->get(hash * 2) != undefined_value() && 3610 number_string_cache()->length() != FullSizeNumberStringCacheLength()) { 3611 // The first time we have a hash collision, we move to the full sized 3612 // number string cache. 3613 AllocateFullSizeNumberStringCache(); 3614 return; 3615 } 3616 number_string_cache()->set(hash * 2, number); 3617 number_string_cache()->set(hash * 2 + 1, string); 3618 } 3619 3620 3621 MaybeObject* Heap::NumberToString(Object* number, 3622 bool check_number_string_cache, 3623 PretenureFlag pretenure) { 3624 isolate_->counters()->number_to_string_runtime()->Increment(); 3625 if (check_number_string_cache) { 3626 Object* cached = GetNumberStringCache(number); 3627 if (cached != undefined_value()) { 3628 return cached; 3629 } 3630 } 3631 3632 char arr[100]; 3633 Vector<char> buffer(arr, ARRAY_SIZE(arr)); 3634 const char* str; 3635 if (number->IsSmi()) { 3636 int num = Smi::cast(number)->value(); 3637 str = IntToCString(num, buffer); 3638 } else { 3639 double num = HeapNumber::cast(number)->value(); 3640 str = DoubleToCString(num, buffer); 3641 } 3642 3643 Object* js_string; 3644 MaybeObject* maybe_js_string = 3645 AllocateStringFromOneByte(CStrVector(str), pretenure); 3646 if (maybe_js_string->ToObject(&js_string)) { 3647 SetNumberStringCache(number, String::cast(js_string)); 3648 } 3649 return maybe_js_string; 3650 } 3651 3652 3653 MaybeObject* Heap::Uint32ToString(uint32_t value, 3654 bool check_number_string_cache) { 3655 Object* number; 3656 MaybeObject* maybe = NumberFromUint32(value); 3657 if (!maybe->To<Object>(&number)) return maybe; 3658 return NumberToString(number, check_number_string_cache); 3659 } 3660 3661 3662 Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) { 3663 return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]); 3664 } 3665 3666 3667 Heap::RootListIndex Heap::RootIndexForExternalArrayType( 3668 ExternalArrayType array_type) { 3669 switch (array_type) { 3670 case kExternalByteArray: 3671 return kExternalByteArrayMapRootIndex; 3672 case kExternalUnsignedByteArray: 3673 return kExternalUnsignedByteArrayMapRootIndex; 3674 case kExternalShortArray: 3675 return kExternalShortArrayMapRootIndex; 3676 case kExternalUnsignedShortArray: 3677 return kExternalUnsignedShortArrayMapRootIndex; 3678 case kExternalIntArray: 3679 return kExternalIntArrayMapRootIndex; 3680 case kExternalUnsignedIntArray: 3681 return kExternalUnsignedIntArrayMapRootIndex; 3682 case kExternalFloatArray: 3683 return kExternalFloatArrayMapRootIndex; 3684 case kExternalDoubleArray: 3685 return kExternalDoubleArrayMapRootIndex; 3686 case kExternalPixelArray: 3687 return kExternalPixelArrayMapRootIndex; 3688 default: 3689 UNREACHABLE(); 3690 return kUndefinedValueRootIndex; 3691 } 3692 } 3693 3694 Heap::RootListIndex Heap::RootIndexForEmptyExternalArray( 3695 ElementsKind elementsKind) { 3696 switch (elementsKind) { 3697 case EXTERNAL_BYTE_ELEMENTS: 3698 return kEmptyExternalByteArrayRootIndex; 3699 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 3700 return kEmptyExternalUnsignedByteArrayRootIndex; 3701 case EXTERNAL_SHORT_ELEMENTS: 3702 return kEmptyExternalShortArrayRootIndex; 3703 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 3704 return kEmptyExternalUnsignedShortArrayRootIndex; 3705 case EXTERNAL_INT_ELEMENTS: 3706 return kEmptyExternalIntArrayRootIndex; 3707 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 3708 return kEmptyExternalUnsignedIntArrayRootIndex; 3709 case EXTERNAL_FLOAT_ELEMENTS: 3710 return kEmptyExternalFloatArrayRootIndex; 3711 case EXTERNAL_DOUBLE_ELEMENTS: 3712 return kEmptyExternalDoubleArrayRootIndex; 3713 case EXTERNAL_PIXEL_ELEMENTS: 3714 return kEmptyExternalPixelArrayRootIndex; 3715 default: 3716 UNREACHABLE(); 3717 return kUndefinedValueRootIndex; 3718 } 3719 } 3720 3721 3722 ExternalArray* Heap::EmptyExternalArrayForMap(Map* map) { 3723 return ExternalArray::cast( 3724 roots_[RootIndexForEmptyExternalArray(map->elements_kind())]); 3725 } 3726 3727 3728 3729 3730 MaybeObject* Heap::NumberFromDouble(double value, PretenureFlag pretenure) { 3731 // We need to distinguish the minus zero value and this cannot be 3732 // done after conversion to int. Doing this by comparing bit 3733 // patterns is faster than using fpclassify() et al. 3734 static const DoubleRepresentation minus_zero(-0.0); 3735 3736 DoubleRepresentation rep(value); 3737 if (rep.bits == minus_zero.bits) { 3738 return AllocateHeapNumber(-0.0, pretenure); 3739 } 3740 3741 int int_value = FastD2I(value); 3742 if (value == int_value && Smi::IsValid(int_value)) { 3743 return Smi::FromInt(int_value); 3744 } 3745 3746 // Materialize the value in the heap. 3747 return AllocateHeapNumber(value, pretenure); 3748 } 3749 3750 3751 MaybeObject* Heap::AllocateForeign(Address address, PretenureFlag pretenure) { 3752 // Statically ensure that it is safe to allocate foreigns in paged spaces. 3753 STATIC_ASSERT(Foreign::kSize <= Page::kMaxNonCodeHeapObjectSize); 3754 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; 3755 Foreign* result; 3756 MaybeObject* maybe_result = Allocate(foreign_map(), space); 3757 if (!maybe_result->To(&result)) return maybe_result; 3758 result->set_foreign_address(address); 3759 return result; 3760 } 3761 3762 3763 MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) { 3764 SharedFunctionInfo* share; 3765 MaybeObject* maybe = Allocate(shared_function_info_map(), OLD_POINTER_SPACE); 3766 if (!maybe->To<SharedFunctionInfo>(&share)) return maybe; 3767 3768 // Set pointer fields. 3769 share->set_name(name); 3770 Code* illegal = isolate_->builtins()->builtin(Builtins::kIllegal); 3771 share->set_code(illegal); 3772 share->set_optimized_code_map(Smi::FromInt(0)); 3773 share->set_scope_info(ScopeInfo::Empty(isolate_)); 3774 Code* construct_stub = 3775 isolate_->builtins()->builtin(Builtins::kJSConstructStubGeneric); 3776 share->set_construct_stub(construct_stub); 3777 share->set_instance_class_name(Object_string()); 3778 share->set_function_data(undefined_value(), SKIP_WRITE_BARRIER); 3779 share->set_script(undefined_value(), SKIP_WRITE_BARRIER); 3780 share->set_debug_info(undefined_value(), SKIP_WRITE_BARRIER); 3781 share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER); 3782 share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER); 3783 share->set_ast_node_count(0); 3784 share->set_counters(0); 3785 3786 // Set integer fields (smi or int, depending on the architecture). 3787 share->set_length(0); 3788 share->set_formal_parameter_count(0); 3789 share->set_expected_nof_properties(0); 3790 share->set_num_literals(0); 3791 share->set_start_position_and_type(0); 3792 share->set_end_position(0); 3793 share->set_function_token_position(0); 3794 // All compiler hints default to false or 0. 3795 share->set_compiler_hints(0); 3796 share->set_opt_count_and_bailout_reason(0); 3797 3798 return share; 3799 } 3800 3801 3802 MaybeObject* Heap::AllocateJSMessageObject(String* type, 3803 JSArray* arguments, 3804 int start_position, 3805 int end_position, 3806 Object* script, 3807 Object* stack_trace, 3808 Object* stack_frames) { 3809 Object* result; 3810 { MaybeObject* maybe_result = Allocate(message_object_map(), NEW_SPACE); 3811 if (!maybe_result->ToObject(&result)) return maybe_result; 3812 } 3813 JSMessageObject* message = JSMessageObject::cast(result); 3814 message->set_properties(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER); 3815 message->initialize_elements(); 3816 message->set_elements(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER); 3817 message->set_type(type); 3818 message->set_arguments(arguments); 3819 message->set_start_position(start_position); 3820 message->set_end_position(end_position); 3821 message->set_script(script); 3822 message->set_stack_trace(stack_trace); 3823 message->set_stack_frames(stack_frames); 3824 return result; 3825 } 3826 3827 3828 3829 // Returns true for a character in a range. Both limits are inclusive. 3830 static inline bool Between(uint32_t character, uint32_t from, uint32_t to) { 3831 // This makes uses of the the unsigned wraparound. 3832 return character - from <= to - from; 3833 } 3834 3835 3836 MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString( 3837 Heap* heap, 3838 uint16_t c1, 3839 uint16_t c2) { 3840 String* result; 3841 // Numeric strings have a different hash algorithm not known by 3842 // LookupTwoCharsStringIfExists, so we skip this step for such strings. 3843 if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) && 3844 heap->string_table()->LookupTwoCharsStringIfExists(c1, c2, &result)) { 3845 return result; 3846 // Now we know the length is 2, we might as well make use of that fact 3847 // when building the new string. 3848 } else if (static_cast<unsigned>(c1 | c2) <= String::kMaxOneByteCharCodeU) { 3849 // We can do this. 3850 ASSERT(IsPowerOf2(String::kMaxOneByteCharCodeU + 1)); // because of this. 3851 Object* result; 3852 { MaybeObject* maybe_result = heap->AllocateRawOneByteString(2); 3853 if (!maybe_result->ToObject(&result)) return maybe_result; 3854 } 3855 uint8_t* dest = SeqOneByteString::cast(result)->GetChars(); 3856 dest[0] = static_cast<uint8_t>(c1); 3857 dest[1] = static_cast<uint8_t>(c2); 3858 return result; 3859 } else { 3860 Object* result; 3861 { MaybeObject* maybe_result = heap->AllocateRawTwoByteString(2); 3862 if (!maybe_result->ToObject(&result)) return maybe_result; 3863 } 3864 uc16* dest = SeqTwoByteString::cast(result)->GetChars(); 3865 dest[0] = c1; 3866 dest[1] = c2; 3867 return result; 3868 } 3869 } 3870 3871 3872 MaybeObject* Heap::AllocateConsString(String* first, String* second) { 3873 int first_length = first->length(); 3874 if (first_length == 0) { 3875 return second; 3876 } 3877 3878 int second_length = second->length(); 3879 if (second_length == 0) { 3880 return first; 3881 } 3882 3883 int length = first_length + second_length; 3884 3885 // Optimization for 2-byte strings often used as keys in a decompression 3886 // dictionary. Check whether we already have the string in the string 3887 // table to prevent creation of many unneccesary strings. 3888 if (length == 2) { 3889 uint16_t c1 = first->Get(0); 3890 uint16_t c2 = second->Get(0); 3891 return MakeOrFindTwoCharacterString(this, c1, c2); 3892 } 3893 3894 bool first_is_one_byte = first->IsOneByteRepresentation(); 3895 bool second_is_one_byte = second->IsOneByteRepresentation(); 3896 bool is_one_byte = first_is_one_byte && second_is_one_byte; 3897 // Make sure that an out of memory exception is thrown if the length 3898 // of the new cons string is too large. 3899 if (length > String::kMaxLength || length < 0) { 3900 isolate()->context()->mark_out_of_memory(); 3901 return Failure::OutOfMemoryException(0x4); 3902 } 3903 3904 bool is_one_byte_data_in_two_byte_string = false; 3905 if (!is_one_byte) { 3906 // At least one of the strings uses two-byte representation so we 3907 // can't use the fast case code for short ASCII strings below, but 3908 // we can try to save memory if all chars actually fit in ASCII. 3909 is_one_byte_data_in_two_byte_string = 3910 first->HasOnlyOneByteChars() && second->HasOnlyOneByteChars(); 3911 if (is_one_byte_data_in_two_byte_string) { 3912 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment(); 3913 } 3914 } 3915 3916 // If the resulting string is small make a flat string. 3917 if (length < ConsString::kMinLength) { 3918 // Note that neither of the two inputs can be a slice because: 3919 STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength); 3920 ASSERT(first->IsFlat()); 3921 ASSERT(second->IsFlat()); 3922 if (is_one_byte) { 3923 Object* result; 3924 { MaybeObject* maybe_result = AllocateRawOneByteString(length); 3925 if (!maybe_result->ToObject(&result)) return maybe_result; 3926 } 3927 // Copy the characters into the new object. 3928 uint8_t* dest = SeqOneByteString::cast(result)->GetChars(); 3929 // Copy first part. 3930 const uint8_t* src; 3931 if (first->IsExternalString()) { 3932 src = ExternalAsciiString::cast(first)->GetChars(); 3933 } else { 3934 src = SeqOneByteString::cast(first)->GetChars(); 3935 } 3936 for (int i = 0; i < first_length; i++) *dest++ = src[i]; 3937 // Copy second part. 3938 if (second->IsExternalString()) { 3939 src = ExternalAsciiString::cast(second)->GetChars(); 3940 } else { 3941 src = SeqOneByteString::cast(second)->GetChars(); 3942 } 3943 for (int i = 0; i < second_length; i++) *dest++ = src[i]; 3944 return result; 3945 } else { 3946 if (is_one_byte_data_in_two_byte_string) { 3947 Object* result; 3948 { MaybeObject* maybe_result = AllocateRawOneByteString(length); 3949 if (!maybe_result->ToObject(&result)) return maybe_result; 3950 } 3951 // Copy the characters into the new object. 3952 uint8_t* dest = SeqOneByteString::cast(result)->GetChars(); 3953 String::WriteToFlat(first, dest, 0, first_length); 3954 String::WriteToFlat(second, dest + first_length, 0, second_length); 3955 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment(); 3956 return result; 3957 } 3958 3959 Object* result; 3960 { MaybeObject* maybe_result = AllocateRawTwoByteString(length); 3961 if (!maybe_result->ToObject(&result)) return maybe_result; 3962 } 3963 // Copy the characters into the new object. 3964 uc16* dest = SeqTwoByteString::cast(result)->GetChars(); 3965 String::WriteToFlat(first, dest, 0, first_length); 3966 String::WriteToFlat(second, dest + first_length, 0, second_length); 3967 return result; 3968 } 3969 } 3970 3971 Map* map = (is_one_byte || is_one_byte_data_in_two_byte_string) ? 3972 cons_ascii_string_map() : cons_string_map(); 3973 3974 Object* result; 3975 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE); 3976 if (!maybe_result->ToObject(&result)) return maybe_result; 3977 } 3978 3979 DisallowHeapAllocation no_gc; 3980 ConsString* cons_string = ConsString::cast(result); 3981 WriteBarrierMode mode = cons_string->GetWriteBarrierMode(no_gc); 3982 cons_string->set_length(length); 3983 cons_string->set_hash_field(String::kEmptyHashField); 3984 cons_string->set_first(first, mode); 3985 cons_string->set_second(second, mode); 3986 return result; 3987 } 3988 3989 3990 MaybeObject* Heap::AllocateSubString(String* buffer, 3991 int start, 3992 int end, 3993 PretenureFlag pretenure) { 3994 int length = end - start; 3995 if (length <= 0) { 3996 return empty_string(); 3997 } 3998 3999 // Make an attempt to flatten the buffer to reduce access time. 4000 buffer = buffer->TryFlattenGetString(); 4001 4002 if (length == 1) { 4003 return LookupSingleCharacterStringFromCode(buffer->Get(start)); 4004 } else if (length == 2) { 4005 // Optimization for 2-byte strings often used as keys in a decompression 4006 // dictionary. Check whether we already have the string in the string 4007 // table to prevent creation of many unnecessary strings. 4008 uint16_t c1 = buffer->Get(start); 4009 uint16_t c2 = buffer->Get(start + 1); 4010 return MakeOrFindTwoCharacterString(this, c1, c2); 4011 } 4012 4013 if (!FLAG_string_slices || 4014 !buffer->IsFlat() || 4015 length < SlicedString::kMinLength || 4016 pretenure == TENURED) { 4017 Object* result; 4018 // WriteToFlat takes care of the case when an indirect string has a 4019 // different encoding from its underlying string. These encodings may 4020 // differ because of externalization. 4021 bool is_one_byte = buffer->IsOneByteRepresentation(); 4022 { MaybeObject* maybe_result = is_one_byte 4023 ? AllocateRawOneByteString(length, pretenure) 4024 : AllocateRawTwoByteString(length, pretenure); 4025 if (!maybe_result->ToObject(&result)) return maybe_result; 4026 } 4027 String* string_result = String::cast(result); 4028 // Copy the characters into the new object. 4029 if (is_one_byte) { 4030 ASSERT(string_result->IsOneByteRepresentation()); 4031 uint8_t* dest = SeqOneByteString::cast(string_result)->GetChars(); 4032 String::WriteToFlat(buffer, dest, start, end); 4033 } else { 4034 ASSERT(string_result->IsTwoByteRepresentation()); 4035 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars(); 4036 String::WriteToFlat(buffer, dest, start, end); 4037 } 4038 return result; 4039 } 4040 4041 ASSERT(buffer->IsFlat()); 4042 #if VERIFY_HEAP 4043 if (FLAG_verify_heap) { 4044 buffer->StringVerify(); 4045 } 4046 #endif 4047 4048 Object* result; 4049 // When slicing an indirect string we use its encoding for a newly created 4050 // slice and don't check the encoding of the underlying string. This is safe 4051 // even if the encodings are different because of externalization. If an 4052 // indirect ASCII string is pointing to a two-byte string, the two-byte char 4053 // codes of the underlying string must still fit into ASCII (because 4054 // externalization must not change char codes). 4055 { Map* map = buffer->IsOneByteRepresentation() 4056 ? sliced_ascii_string_map() 4057 : sliced_string_map(); 4058 MaybeObject* maybe_result = Allocate(map, NEW_SPACE); 4059 if (!maybe_result->ToObject(&result)) return maybe_result; 4060 } 4061 4062 DisallowHeapAllocation no_gc; 4063 SlicedString* sliced_string = SlicedString::cast(result); 4064 sliced_string->set_length(length); 4065 sliced_string->set_hash_field(String::kEmptyHashField); 4066 if (buffer->IsConsString()) { 4067 ConsString* cons = ConsString::cast(buffer); 4068 ASSERT(cons->second()->length() == 0); 4069 sliced_string->set_parent(cons->first()); 4070 sliced_string->set_offset(start); 4071 } else if (buffer->IsSlicedString()) { 4072 // Prevent nesting sliced strings. 4073 SlicedString* parent_slice = SlicedString::cast(buffer); 4074 sliced_string->set_parent(parent_slice->parent()); 4075 sliced_string->set_offset(start + parent_slice->offset()); 4076 } else { 4077 sliced_string->set_parent(buffer); 4078 sliced_string->set_offset(start); 4079 } 4080 ASSERT(sliced_string->parent()->IsSeqString() || 4081 sliced_string->parent()->IsExternalString()); 4082 return result; 4083 } 4084 4085 4086 MaybeObject* Heap::AllocateExternalStringFromAscii( 4087 const ExternalAsciiString::Resource* resource) { 4088 size_t length = resource->length(); 4089 if (length > static_cast<size_t>(String::kMaxLength)) { 4090 isolate()->context()->mark_out_of_memory(); 4091 return Failure::OutOfMemoryException(0x5); 4092 } 4093 4094 Map* map = external_ascii_string_map(); 4095 Object* result; 4096 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE); 4097 if (!maybe_result->ToObject(&result)) return maybe_result; 4098 } 4099 4100 ExternalAsciiString* external_string = ExternalAsciiString::cast(result); 4101 external_string->set_length(static_cast<int>(length)); 4102 external_string->set_hash_field(String::kEmptyHashField); 4103 external_string->set_resource(resource); 4104 4105 return result; 4106 } 4107 4108 4109 MaybeObject* Heap::AllocateExternalStringFromTwoByte( 4110 const ExternalTwoByteString::Resource* resource) { 4111 size_t length = resource->length(); 4112 if (length > static_cast<size_t>(String::kMaxLength)) { 4113 isolate()->context()->mark_out_of_memory(); 4114 return Failure::OutOfMemoryException(0x6); 4115 } 4116 4117 // For small strings we check whether the resource contains only 4118 // one byte characters. If yes, we use a different string map. 4119 static const size_t kOneByteCheckLengthLimit = 32; 4120 bool is_one_byte = length <= kOneByteCheckLengthLimit && 4121 String::IsOneByte(resource->data(), static_cast<int>(length)); 4122 Map* map = is_one_byte ? 4123 external_string_with_one_byte_data_map() : external_string_map(); 4124 Object* result; 4125 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE); 4126 if (!maybe_result->ToObject(&result)) return maybe_result; 4127 } 4128 4129 ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result); 4130 external_string->set_length(static_cast<int>(length)); 4131 external_string->set_hash_field(String::kEmptyHashField); 4132 external_string->set_resource(resource); 4133 4134 return result; 4135 } 4136 4137 4138 MaybeObject* Heap::LookupSingleCharacterStringFromCode(uint16_t code) { 4139 if (code <= String::kMaxOneByteCharCode) { 4140 Object* value = single_character_string_cache()->get(code); 4141 if (value != undefined_value()) return value; 4142 4143 uint8_t buffer[1]; 4144 buffer[0] = static_cast<uint8_t>(code); 4145 Object* result; 4146 MaybeObject* maybe_result = 4147 InternalizeOneByteString(Vector<const uint8_t>(buffer, 1)); 4148 4149 if (!maybe_result->ToObject(&result)) return maybe_result; 4150 single_character_string_cache()->set(code, result); 4151 return result; 4152 } 4153 4154 SeqTwoByteString* result; 4155 { MaybeObject* maybe_result = AllocateRawTwoByteString(1); 4156 if (!maybe_result->To<SeqTwoByteString>(&result)) return maybe_result; 4157 } 4158 result->SeqTwoByteStringSet(0, code); 4159 return result; 4160 } 4161 4162 4163 MaybeObject* Heap::AllocateByteArray(int length, PretenureFlag pretenure) { 4164 if (length < 0 || length > ByteArray::kMaxLength) { 4165 return Failure::OutOfMemoryException(0x7); 4166 } 4167 int size = ByteArray::SizeFor(length); 4168 AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); 4169 Object* result; 4170 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE); 4171 if (!maybe_result->ToObject(&result)) return maybe_result; 4172 } 4173 4174 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier( 4175 byte_array_map()); 4176 reinterpret_cast<ByteArray*>(result)->set_length(length); 4177 return result; 4178 } 4179 4180 4181 void Heap::CreateFillerObjectAt(Address addr, int size) { 4182 if (size == 0) return; 4183 HeapObject* filler = HeapObject::FromAddress(addr); 4184 if (size == kPointerSize) { 4185 filler->set_map_no_write_barrier(one_pointer_filler_map()); 4186 } else if (size == 2 * kPointerSize) { 4187 filler->set_map_no_write_barrier(two_pointer_filler_map()); 4188 } else { 4189 filler->set_map_no_write_barrier(free_space_map()); 4190 FreeSpace::cast(filler)->set_size(size); 4191 } 4192 } 4193 4194 4195 MaybeObject* Heap::AllocateExternalArray(int length, 4196 ExternalArrayType array_type, 4197 void* external_pointer, 4198 PretenureFlag pretenure) { 4199 int size = ExternalArray::kAlignedSize; 4200 AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); 4201 Object* result; 4202 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE); 4203 if (!maybe_result->ToObject(&result)) return maybe_result; 4204 } 4205 4206 reinterpret_cast<ExternalArray*>(result)->set_map_no_write_barrier( 4207 MapForExternalArrayType(array_type)); 4208 reinterpret_cast<ExternalArray*>(result)->set_length(length); 4209 reinterpret_cast<ExternalArray*>(result)->set_external_pointer( 4210 external_pointer); 4211 4212 return result; 4213 } 4214 4215 4216 MaybeObject* Heap::CreateCode(const CodeDesc& desc, 4217 Code::Flags flags, 4218 Handle<Object> self_reference, 4219 bool immovable, 4220 bool crankshafted, 4221 int prologue_offset) { 4222 // Allocate ByteArray before the Code object, so that we do not risk 4223 // leaving uninitialized Code object (and breaking the heap). 4224 ByteArray* reloc_info; 4225 MaybeObject* maybe_reloc_info = AllocateByteArray(desc.reloc_size, TENURED); 4226 if (!maybe_reloc_info->To(&reloc_info)) return maybe_reloc_info; 4227 4228 // Compute size. 4229 int body_size = RoundUp(desc.instr_size, kObjectAlignment); 4230 int obj_size = Code::SizeFor(body_size); 4231 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment)); 4232 MaybeObject* maybe_result; 4233 // Large code objects and code objects which should stay at a fixed address 4234 // are allocated in large object space. 4235 HeapObject* result; 4236 bool force_lo_space = obj_size > code_space()->AreaSize(); 4237 if (force_lo_space) { 4238 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); 4239 } else { 4240 maybe_result = AllocateRaw(obj_size, CODE_SPACE, CODE_SPACE); 4241 } 4242 if (!maybe_result->To<HeapObject>(&result)) return maybe_result; 4243 4244 if (immovable && !force_lo_space && 4245 // Objects on the first page of each space are never moved. 4246 !code_space_->FirstPage()->Contains(result->address())) { 4247 // Discard the first code allocation, which was on a page where it could be 4248 // moved. 4249 CreateFillerObjectAt(result->address(), obj_size); 4250 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); 4251 if (!maybe_result->To<HeapObject>(&result)) return maybe_result; 4252 } 4253 4254 // Initialize the object 4255 result->set_map_no_write_barrier(code_map()); 4256 Code* code = Code::cast(result); 4257 ASSERT(!isolate_->code_range()->exists() || 4258 isolate_->code_range()->contains(code->address())); 4259 code->set_instruction_size(desc.instr_size); 4260 code->set_relocation_info(reloc_info); 4261 code->set_flags(flags); 4262 code->set_raw_kind_specific_flags1(0); 4263 code->set_raw_kind_specific_flags2(0); 4264 if (code->is_call_stub() || code->is_keyed_call_stub()) { 4265 code->set_check_type(RECEIVER_MAP_CHECK); 4266 } 4267 code->set_is_crankshafted(crankshafted); 4268 code->set_deoptimization_data(empty_fixed_array(), SKIP_WRITE_BARRIER); 4269 code->set_raw_type_feedback_info(undefined_value()); 4270 code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER); 4271 code->set_gc_metadata(Smi::FromInt(0)); 4272 code->set_ic_age(global_ic_age_); 4273 code->set_prologue_offset(prologue_offset); 4274 if (code->kind() == Code::OPTIMIZED_FUNCTION) { 4275 code->set_marked_for_deoptimization(false); 4276 } 4277 4278 #ifdef ENABLE_DEBUGGER_SUPPORT 4279 if (code->kind() == Code::FUNCTION) { 4280 code->set_has_debug_break_slots( 4281 isolate_->debugger()->IsDebuggerActive()); 4282 } 4283 #endif 4284 4285 // Allow self references to created code object by patching the handle to 4286 // point to the newly allocated Code object. 4287 if (!self_reference.is_null()) { 4288 *(self_reference.location()) = code; 4289 } 4290 // Migrate generated code. 4291 // The generated code can contain Object** values (typically from handles) 4292 // that are dereferenced during the copy to point directly to the actual heap 4293 // objects. These pointers can include references to the code object itself, 4294 // through the self_reference parameter. 4295 code->CopyFrom(desc); 4296 4297 #ifdef VERIFY_HEAP 4298 if (FLAG_verify_heap) { 4299 code->Verify(); 4300 } 4301 #endif 4302 return code; 4303 } 4304 4305 4306 MaybeObject* Heap::CopyCode(Code* code) { 4307 // Allocate an object the same size as the code object. 4308 int obj_size = code->Size(); 4309 MaybeObject* maybe_result; 4310 if (obj_size > code_space()->AreaSize()) { 4311 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE); 4312 } else { 4313 maybe_result = AllocateRaw(obj_size, CODE_SPACE, CODE_SPACE); 4314 } 4315 4316 Object* result; 4317 if (!maybe_result->ToObject(&result)) return maybe_result; 4318 4319 // Copy code object. 4320 Address old_addr = code->address(); 4321 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); 4322 CopyBlock(new_addr, old_addr, obj_size); 4323 // Relocate the copy. 4324 Code* new_code = Code::cast(result); 4325 ASSERT(!isolate_->code_range()->exists() || 4326 isolate_->code_range()->contains(code->address())); 4327 new_code->Relocate(new_addr - old_addr); 4328 return new_code; 4329 } 4330 4331 4332 MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) { 4333 // Allocate ByteArray before the Code object, so that we do not risk 4334 // leaving uninitialized Code object (and breaking the heap). 4335 Object* reloc_info_array; 4336 { MaybeObject* maybe_reloc_info_array = 4337 AllocateByteArray(reloc_info.length(), TENURED); 4338 if (!maybe_reloc_info_array->ToObject(&reloc_info_array)) { 4339 return maybe_reloc_info_array; 4340 } 4341 } 4342 4343 int new_body_size = RoundUp(code->instruction_size(), kObjectAlignment); 4344 4345 int new_obj_size = Code::SizeFor(new_body_size); 4346 4347 Address old_addr = code->address(); 4348 4349 size_t relocation_offset = 4350 static_cast<size_t>(code->instruction_end() - old_addr); 4351 4352 MaybeObject* maybe_result; 4353 if (new_obj_size > code_space()->AreaSize()) { 4354 maybe_result = lo_space_->AllocateRaw(new_obj_size, EXECUTABLE); 4355 } else { 4356 maybe_result = AllocateRaw(new_obj_size, CODE_SPACE, CODE_SPACE); 4357 } 4358 4359 Object* result; 4360 if (!maybe_result->ToObject(&result)) return maybe_result; 4361 4362 // Copy code object. 4363 Address new_addr = reinterpret_cast<HeapObject*>(result)->address(); 4364 4365 // Copy header and instructions. 4366 CopyBytes(new_addr, old_addr, relocation_offset); 4367 4368 Code* new_code = Code::cast(result); 4369 new_code->set_relocation_info(ByteArray::cast(reloc_info_array)); 4370 4371 // Copy patched rinfo. 4372 CopyBytes(new_code->relocation_start(), 4373 reloc_info.start(), 4374 static_cast<size_t>(reloc_info.length())); 4375 4376 // Relocate the copy. 4377 ASSERT(!isolate_->code_range()->exists() || 4378 isolate_->code_range()->contains(code->address())); 4379 new_code->Relocate(new_addr - old_addr); 4380 4381 #ifdef VERIFY_HEAP 4382 if (FLAG_verify_heap) { 4383 code->Verify(); 4384 } 4385 #endif 4386 return new_code; 4387 } 4388 4389 4390 void Heap::InitializeAllocationMemento(AllocationMemento* memento, 4391 AllocationSite* allocation_site) { 4392 memento->set_map_no_write_barrier(allocation_memento_map()); 4393 ASSERT(allocation_site->map() == allocation_site_map()); 4394 memento->set_allocation_site(allocation_site, SKIP_WRITE_BARRIER); 4395 if (FLAG_allocation_site_pretenuring) { 4396 allocation_site->IncrementMementoCreateCount(); 4397 } 4398 } 4399 4400 4401 MaybeObject* Heap::AllocateWithAllocationSite(Map* map, AllocationSpace space, 4402 Handle<AllocationSite> allocation_site) { 4403 ASSERT(gc_state_ == NOT_IN_GC); 4404 ASSERT(map->instance_type() != MAP_TYPE); 4405 // If allocation failures are disallowed, we may allocate in a different 4406 // space when new space is full and the object is not a large object. 4407 AllocationSpace retry_space = 4408 (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type()); 4409 int size = map->instance_size() + AllocationMemento::kSize; 4410 Object* result; 4411 MaybeObject* maybe_result = AllocateRaw(size, space, retry_space); 4412 if (!maybe_result->ToObject(&result)) return maybe_result; 4413 // No need for write barrier since object is white and map is in old space. 4414 HeapObject::cast(result)->set_map_no_write_barrier(map); 4415 AllocationMemento* alloc_memento = reinterpret_cast<AllocationMemento*>( 4416 reinterpret_cast<Address>(result) + map->instance_size()); 4417 InitializeAllocationMemento(alloc_memento, *allocation_site); 4418 return result; 4419 } 4420 4421 4422 MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) { 4423 ASSERT(gc_state_ == NOT_IN_GC); 4424 ASSERT(map->instance_type() != MAP_TYPE); 4425 // If allocation failures are disallowed, we may allocate in a different 4426 // space when new space is full and the object is not a large object. 4427 AllocationSpace retry_space = 4428 (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type()); 4429 int size = map->instance_size(); 4430 Object* result; 4431 MaybeObject* maybe_result = AllocateRaw(size, space, retry_space); 4432 if (!maybe_result->ToObject(&result)) return maybe_result; 4433 // No need for write barrier since object is white and map is in old space. 4434 HeapObject::cast(result)->set_map_no_write_barrier(map); 4435 return result; 4436 } 4437 4438 4439 void Heap::InitializeFunction(JSFunction* function, 4440 SharedFunctionInfo* shared, 4441 Object* prototype) { 4442 ASSERT(!prototype->IsMap()); 4443 function->initialize_properties(); 4444 function->initialize_elements(); 4445 function->set_shared(shared); 4446 function->set_code(shared->code()); 4447 function->set_prototype_or_initial_map(prototype); 4448 function->set_context(undefined_value()); 4449 function->set_literals_or_bindings(empty_fixed_array()); 4450 function->set_next_function_link(undefined_value()); 4451 } 4452 4453 4454 MaybeObject* Heap::AllocateFunction(Map* function_map, 4455 SharedFunctionInfo* shared, 4456 Object* prototype, 4457 PretenureFlag pretenure) { 4458 AllocationSpace space = 4459 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE; 4460 Object* result; 4461 { MaybeObject* maybe_result = Allocate(function_map, space); 4462 if (!maybe_result->ToObject(&result)) return maybe_result; 4463 } 4464 InitializeFunction(JSFunction::cast(result), shared, prototype); 4465 return result; 4466 } 4467 4468 4469 MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) { 4470 // To get fast allocation and map sharing for arguments objects we 4471 // allocate them based on an arguments boilerplate. 4472 4473 JSObject* boilerplate; 4474 int arguments_object_size; 4475 bool strict_mode_callee = callee->IsJSFunction() && 4476 !JSFunction::cast(callee)->shared()->is_classic_mode(); 4477 if (strict_mode_callee) { 4478 boilerplate = 4479 isolate()->context()->native_context()-> 4480 strict_mode_arguments_boilerplate(); 4481 arguments_object_size = kArgumentsObjectSizeStrict; 4482 } else { 4483 boilerplate = 4484 isolate()->context()->native_context()->arguments_boilerplate(); 4485 arguments_object_size = kArgumentsObjectSize; 4486 } 4487 4488 // Check that the size of the boilerplate matches our 4489 // expectations. The ArgumentsAccessStub::GenerateNewObject relies 4490 // on the size being a known constant. 4491 ASSERT(arguments_object_size == boilerplate->map()->instance_size()); 4492 4493 // Do the allocation. 4494 Object* result; 4495 { MaybeObject* maybe_result = 4496 AllocateRaw(arguments_object_size, NEW_SPACE, OLD_POINTER_SPACE); 4497 if (!maybe_result->ToObject(&result)) return maybe_result; 4498 } 4499 4500 // Copy the content. The arguments boilerplate doesn't have any 4501 // fields that point to new space so it's safe to skip the write 4502 // barrier here. 4503 CopyBlock(HeapObject::cast(result)->address(), 4504 boilerplate->address(), 4505 JSObject::kHeaderSize); 4506 4507 // Set the length property. 4508 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsLengthIndex, 4509 Smi::FromInt(length), 4510 SKIP_WRITE_BARRIER); 4511 // Set the callee property for non-strict mode arguments object only. 4512 if (!strict_mode_callee) { 4513 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsCalleeIndex, 4514 callee); 4515 } 4516 4517 // Check the state of the object 4518 ASSERT(JSObject::cast(result)->HasFastProperties()); 4519 ASSERT(JSObject::cast(result)->HasFastObjectElements()); 4520 4521 return result; 4522 } 4523 4524 4525 void Heap::InitializeJSObjectFromMap(JSObject* obj, 4526 FixedArray* properties, 4527 Map* map) { 4528 obj->set_properties(properties); 4529 obj->initialize_elements(); 4530 // TODO(1240798): Initialize the object's body using valid initial values 4531 // according to the object's initial map. For example, if the map's 4532 // instance type is JS_ARRAY_TYPE, the length field should be initialized 4533 // to a number (e.g. Smi::FromInt(0)) and the elements initialized to a 4534 // fixed array (e.g. Heap::empty_fixed_array()). Currently, the object 4535 // verification code has to cope with (temporarily) invalid objects. See 4536 // for example, JSArray::JSArrayVerify). 4537 Object* filler; 4538 // We cannot always fill with one_pointer_filler_map because objects 4539 // created from API functions expect their internal fields to be initialized 4540 // with undefined_value. 4541 // Pre-allocated fields need to be initialized with undefined_value as well 4542 // so that object accesses before the constructor completes (e.g. in the 4543 // debugger) will not cause a crash. 4544 if (map->constructor()->IsJSFunction() && 4545 JSFunction::cast(map->constructor())->shared()-> 4546 IsInobjectSlackTrackingInProgress()) { 4547 // We might want to shrink the object later. 4548 ASSERT(obj->GetInternalFieldCount() == 0); 4549 filler = Heap::one_pointer_filler_map(); 4550 } else { 4551 filler = Heap::undefined_value(); 4552 } 4553 obj->InitializeBody(map, Heap::undefined_value(), filler); 4554 } 4555 4556 4557 MaybeObject* Heap::AllocateJSObjectFromMap( 4558 Map* map, PretenureFlag pretenure, bool allocate_properties) { 4559 // JSFunctions should be allocated using AllocateFunction to be 4560 // properly initialized. 4561 ASSERT(map->instance_type() != JS_FUNCTION_TYPE); 4562 4563 // Both types of global objects should be allocated using 4564 // AllocateGlobalObject to be properly initialized. 4565 ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE); 4566 ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE); 4567 4568 // Allocate the backing storage for the properties. 4569 FixedArray* properties; 4570 if (allocate_properties) { 4571 int prop_size = map->InitialPropertiesLength(); 4572 ASSERT(prop_size >= 0); 4573 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, pretenure); 4574 if (!maybe_properties->To(&properties)) return maybe_properties; 4575 } 4576 } else { 4577 properties = empty_fixed_array(); 4578 } 4579 4580 // Allocate the JSObject. 4581 int size = map->instance_size(); 4582 AllocationSpace space = SelectSpace(size, OLD_POINTER_SPACE, pretenure); 4583 Object* obj; 4584 MaybeObject* maybe_obj = Allocate(map, space); 4585 if (!maybe_obj->To(&obj)) return maybe_obj; 4586 4587 // Initialize the JSObject. 4588 InitializeJSObjectFromMap(JSObject::cast(obj), properties, map); 4589 ASSERT(JSObject::cast(obj)->HasFastElements() || 4590 JSObject::cast(obj)->HasExternalArrayElements()); 4591 return obj; 4592 } 4593 4594 4595 MaybeObject* Heap::AllocateJSObjectFromMapWithAllocationSite( 4596 Map* map, Handle<AllocationSite> allocation_site) { 4597 // JSFunctions should be allocated using AllocateFunction to be 4598 // properly initialized. 4599 ASSERT(map->instance_type() != JS_FUNCTION_TYPE); 4600 4601 // Both types of global objects should be allocated using 4602 // AllocateGlobalObject to be properly initialized. 4603 ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE); 4604 ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE); 4605 4606 // Allocate the backing storage for the properties. 4607 int prop_size = map->InitialPropertiesLength(); 4608 ASSERT(prop_size >= 0); 4609 FixedArray* properties; 4610 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size); 4611 if (!maybe_properties->To(&properties)) return maybe_properties; 4612 } 4613 4614 // Allocate the JSObject. 4615 int size = map->instance_size(); 4616 AllocationSpace space = SelectSpace(size, OLD_POINTER_SPACE, NOT_TENURED); 4617 Object* obj; 4618 MaybeObject* maybe_obj = 4619 AllocateWithAllocationSite(map, space, allocation_site); 4620 if (!maybe_obj->To(&obj)) return maybe_obj; 4621 4622 // Initialize the JSObject. 4623 InitializeJSObjectFromMap(JSObject::cast(obj), properties, map); 4624 ASSERT(JSObject::cast(obj)->HasFastElements()); 4625 return obj; 4626 } 4627 4628 4629 MaybeObject* Heap::AllocateJSObject(JSFunction* constructor, 4630 PretenureFlag pretenure) { 4631 ASSERT(constructor->has_initial_map()); 4632 // Allocate the object based on the constructors initial map. 4633 MaybeObject* result = AllocateJSObjectFromMap( 4634 constructor->initial_map(), pretenure); 4635 #ifdef DEBUG 4636 // Make sure result is NOT a global object if valid. 4637 Object* non_failure; 4638 ASSERT(!result->ToObject(&non_failure) || !non_failure->IsGlobalObject()); 4639 #endif 4640 return result; 4641 } 4642 4643 4644 MaybeObject* Heap::AllocateJSObjectWithAllocationSite(JSFunction* constructor, 4645 Handle<AllocationSite> allocation_site) { 4646 ASSERT(constructor->has_initial_map()); 4647 // Allocate the object based on the constructors initial map, or the payload 4648 // advice 4649 Map* initial_map = constructor->initial_map(); 4650 4651 ElementsKind to_kind = allocation_site->GetElementsKind(); 4652 AllocationSiteMode mode = TRACK_ALLOCATION_SITE; 4653 if (to_kind != initial_map->elements_kind()) { 4654 MaybeObject* maybe_new_map = initial_map->AsElementsKind(to_kind); 4655 if (!maybe_new_map->To(&initial_map)) return maybe_new_map; 4656 // Possibly alter the mode, since we found an updated elements kind 4657 // in the type info cell. 4658 mode = AllocationSite::GetMode(to_kind); 4659 } 4660 4661 MaybeObject* result; 4662 if (mode == TRACK_ALLOCATION_SITE) { 4663 result = AllocateJSObjectFromMapWithAllocationSite(initial_map, 4664 allocation_site); 4665 } else { 4666 result = AllocateJSObjectFromMap(initial_map, NOT_TENURED); 4667 } 4668 #ifdef DEBUG 4669 // Make sure result is NOT a global object if valid. 4670 Object* non_failure; 4671 ASSERT(!result->ToObject(&non_failure) || !non_failure->IsGlobalObject()); 4672 #endif 4673 return result; 4674 } 4675 4676 4677 MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) { 4678 // Allocate a fresh map. Modules do not have a prototype. 4679 Map* map; 4680 MaybeObject* maybe_map = AllocateMap(JS_MODULE_TYPE, JSModule::kSize); 4681 if (!maybe_map->To(&map)) return maybe_map; 4682 // Allocate the object based on the map. 4683 JSModule* module; 4684 MaybeObject* maybe_module = AllocateJSObjectFromMap(map, TENURED); 4685 if (!maybe_module->To(&module)) return maybe_module; 4686 module->set_context(context); 4687 module->set_scope_info(scope_info); 4688 return module; 4689 } 4690 4691 4692 MaybeObject* Heap::AllocateJSArrayAndStorage( 4693 ElementsKind elements_kind, 4694 int length, 4695 int capacity, 4696 ArrayStorageAllocationMode mode, 4697 PretenureFlag pretenure) { 4698 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure); 4699 JSArray* array; 4700 if (!maybe_array->To(&array)) return maybe_array; 4701 4702 // TODO(mvstanton): this body of code is duplicate with AllocateJSArrayStorage 4703 // for performance reasons. 4704 ASSERT(capacity >= length); 4705 4706 if (capacity == 0) { 4707 array->set_length(Smi::FromInt(0)); 4708 array->set_elements(empty_fixed_array()); 4709 return array; 4710 } 4711 4712 FixedArrayBase* elms; 4713 MaybeObject* maybe_elms = NULL; 4714 if (IsFastDoubleElementsKind(elements_kind)) { 4715 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) { 4716 maybe_elms = AllocateUninitializedFixedDoubleArray(capacity); 4717 } else { 4718 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); 4719 maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity); 4720 } 4721 } else { 4722 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind)); 4723 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) { 4724 maybe_elms = AllocateUninitializedFixedArray(capacity); 4725 } else { 4726 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); 4727 maybe_elms = AllocateFixedArrayWithHoles(capacity); 4728 } 4729 } 4730 if (!maybe_elms->To(&elms)) return maybe_elms; 4731 4732 array->set_elements(elms); 4733 array->set_length(Smi::FromInt(length)); 4734 return array; 4735 } 4736 4737 4738 MaybeObject* Heap::AllocateJSArrayStorage( 4739 JSArray* array, 4740 int length, 4741 int capacity, 4742 ArrayStorageAllocationMode mode) { 4743 ASSERT(capacity >= length); 4744 4745 if (capacity == 0) { 4746 array->set_length(Smi::FromInt(0)); 4747 array->set_elements(empty_fixed_array()); 4748 return array; 4749 } 4750 4751 FixedArrayBase* elms; 4752 MaybeObject* maybe_elms = NULL; 4753 ElementsKind elements_kind = array->GetElementsKind(); 4754 if (IsFastDoubleElementsKind(elements_kind)) { 4755 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) { 4756 maybe_elms = AllocateUninitializedFixedDoubleArray(capacity); 4757 } else { 4758 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); 4759 maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity); 4760 } 4761 } else { 4762 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind)); 4763 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) { 4764 maybe_elms = AllocateUninitializedFixedArray(capacity); 4765 } else { 4766 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); 4767 maybe_elms = AllocateFixedArrayWithHoles(capacity); 4768 } 4769 } 4770 if (!maybe_elms->To(&elms)) return maybe_elms; 4771 4772 array->set_elements(elms); 4773 array->set_length(Smi::FromInt(length)); 4774 return array; 4775 } 4776 4777 4778 MaybeObject* Heap::AllocateJSArrayWithElements( 4779 FixedArrayBase* elements, 4780 ElementsKind elements_kind, 4781 int length, 4782 PretenureFlag pretenure) { 4783 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure); 4784 JSArray* array; 4785 if (!maybe_array->To(&array)) return maybe_array; 4786 4787 array->set_elements(elements); 4788 array->set_length(Smi::FromInt(length)); 4789 array->ValidateElements(); 4790 return array; 4791 } 4792 4793 4794 MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) { 4795 // Allocate map. 4796 // TODO(rossberg): Once we optimize proxies, think about a scheme to share 4797 // maps. Will probably depend on the identity of the handler object, too. 4798 Map* map; 4799 MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize); 4800 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj; 4801 map->set_prototype(prototype); 4802 4803 // Allocate the proxy object. 4804 JSProxy* result; 4805 MaybeObject* maybe_result = Allocate(map, NEW_SPACE); 4806 if (!maybe_result->To<JSProxy>(&result)) return maybe_result; 4807 result->InitializeBody(map->instance_size(), Smi::FromInt(0)); 4808 result->set_handler(handler); 4809 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER); 4810 return result; 4811 } 4812 4813 4814 MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler, 4815 Object* call_trap, 4816 Object* construct_trap, 4817 Object* prototype) { 4818 // Allocate map. 4819 // TODO(rossberg): Once we optimize proxies, think about a scheme to share 4820 // maps. Will probably depend on the identity of the handler object, too. 4821 Map* map; 4822 MaybeObject* maybe_map_obj = 4823 AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize); 4824 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj; 4825 map->set_prototype(prototype); 4826 4827 // Allocate the proxy object. 4828 JSFunctionProxy* result; 4829 MaybeObject* maybe_result = Allocate(map, NEW_SPACE); 4830 if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result; 4831 result->InitializeBody(map->instance_size(), Smi::FromInt(0)); 4832 result->set_handler(handler); 4833 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER); 4834 result->set_call_trap(call_trap); 4835 result->set_construct_trap(construct_trap); 4836 return result; 4837 } 4838 4839 4840 MaybeObject* Heap::CopyJSObject(JSObject* source, AllocationSite* site) { 4841 // Never used to copy functions. If functions need to be copied we 4842 // have to be careful to clear the literals array. 4843 SLOW_ASSERT(!source->IsJSFunction()); 4844 4845 // Make the clone. 4846 Map* map = source->map(); 4847 int object_size = map->instance_size(); 4848 Object* clone; 4849 4850 ASSERT(site == NULL || AllocationSite::CanTrack(map->instance_type())); 4851 4852 WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER; 4853 4854 // If we're forced to always allocate, we use the general allocation 4855 // functions which may leave us with an object in old space. 4856 if (always_allocate()) { 4857 { MaybeObject* maybe_clone = 4858 AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE); 4859 if (!maybe_clone->ToObject(&clone)) return maybe_clone; 4860 } 4861 Address clone_address = HeapObject::cast(clone)->address(); 4862 CopyBlock(clone_address, 4863 source->address(), 4864 object_size); 4865 // Update write barrier for all fields that lie beyond the header. 4866 RecordWrites(clone_address, 4867 JSObject::kHeaderSize, 4868 (object_size - JSObject::kHeaderSize) / kPointerSize); 4869 } else { 4870 wb_mode = SKIP_WRITE_BARRIER; 4871 4872 { int adjusted_object_size = site != NULL 4873 ? object_size + AllocationMemento::kSize 4874 : object_size; 4875 MaybeObject* maybe_clone = 4876 AllocateRaw(adjusted_object_size, NEW_SPACE, NEW_SPACE); 4877 if (!maybe_clone->ToObject(&clone)) return maybe_clone; 4878 } 4879 SLOW_ASSERT(InNewSpace(clone)); 4880 // Since we know the clone is allocated in new space, we can copy 4881 // the contents without worrying about updating the write barrier. 4882 CopyBlock(HeapObject::cast(clone)->address(), 4883 source->address(), 4884 object_size); 4885 4886 if (site != NULL) { 4887 AllocationMemento* alloc_memento = reinterpret_cast<AllocationMemento*>( 4888 reinterpret_cast<Address>(clone) + object_size); 4889 InitializeAllocationMemento(alloc_memento, site); 4890 } 4891 } 4892 4893 SLOW_ASSERT( 4894 JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind()); 4895 FixedArrayBase* elements = FixedArrayBase::cast(source->elements()); 4896 FixedArray* properties = FixedArray::cast(source->properties()); 4897 // Update elements if necessary. 4898 if (elements->length() > 0) { 4899 Object* elem; 4900 { MaybeObject* maybe_elem; 4901 if (elements->map() == fixed_cow_array_map()) { 4902 maybe_elem = FixedArray::cast(elements); 4903 } else if (source->HasFastDoubleElements()) { 4904 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements)); 4905 } else { 4906 maybe_elem = CopyFixedArray(FixedArray::cast(elements)); 4907 } 4908 if (!maybe_elem->ToObject(&elem)) return maybe_elem; 4909 } 4910 JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode); 4911 } 4912 // Update properties if necessary. 4913 if (properties->length() > 0) { 4914 Object* prop; 4915 { MaybeObject* maybe_prop = CopyFixedArray(properties); 4916 if (!maybe_prop->ToObject(&prop)) return maybe_prop; 4917 } 4918 JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode); 4919 } 4920 // Return the new clone. 4921 return clone; 4922 } 4923 4924 4925 MaybeObject* Heap::ReinitializeJSReceiver( 4926 JSReceiver* object, InstanceType type, int size) { 4927 ASSERT(type >= FIRST_JS_OBJECT_TYPE); 4928 4929 // Allocate fresh map. 4930 // TODO(rossberg): Once we optimize proxies, cache these maps. 4931 Map* map; 4932 MaybeObject* maybe = AllocateMap(type, size); 4933 if (!maybe->To<Map>(&map)) return maybe; 4934 4935 // Check that the receiver has at least the size of the fresh object. 4936 int size_difference = object->map()->instance_size() - map->instance_size(); 4937 ASSERT(size_difference >= 0); 4938 4939 map->set_prototype(object->map()->prototype()); 4940 4941 // Allocate the backing storage for the properties. 4942 int prop_size = map->unused_property_fields() - map->inobject_properties(); 4943 Object* properties; 4944 maybe = AllocateFixedArray(prop_size, TENURED); 4945 if (!maybe->ToObject(&properties)) return maybe; 4946 4947 // Functions require some allocation, which might fail here. 4948 SharedFunctionInfo* shared = NULL; 4949 if (type == JS_FUNCTION_TYPE) { 4950 String* name; 4951 maybe = 4952 InternalizeOneByteString(STATIC_ASCII_VECTOR("<freezing call trap>")); 4953 if (!maybe->To<String>(&name)) return maybe; 4954 maybe = AllocateSharedFunctionInfo(name); 4955 if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe; 4956 } 4957 4958 // Because of possible retries of this function after failure, 4959 // we must NOT fail after this point, where we have changed the type! 4960 4961 // Reset the map for the object. 4962 object->set_map(map); 4963 JSObject* jsobj = JSObject::cast(object); 4964 4965 // Reinitialize the object from the constructor map. 4966 InitializeJSObjectFromMap(jsobj, FixedArray::cast(properties), map); 4967 4968 // Functions require some minimal initialization. 4969 if (type == JS_FUNCTION_TYPE) { 4970 map->set_function_with_prototype(true); 4971 InitializeFunction(JSFunction::cast(object), shared, the_hole_value()); 4972 JSFunction::cast(object)->set_context( 4973 isolate()->context()->native_context()); 4974 } 4975 4976 // Put in filler if the new object is smaller than the old. 4977 if (size_difference > 0) { 4978 CreateFillerObjectAt( 4979 object->address() + map->instance_size(), size_difference); 4980 } 4981 4982 return object; 4983 } 4984 4985 4986 MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor, 4987 JSGlobalProxy* object) { 4988 ASSERT(constructor->has_initial_map()); 4989 Map* map = constructor->initial_map(); 4990 4991 // Check that the already allocated object has the same size and type as 4992 // objects allocated using the constructor. 4993 ASSERT(map->instance_size() == object->map()->instance_size()); 4994 ASSERT(map->instance_type() == object->map()->instance_type()); 4995 4996 // Allocate the backing storage for the properties. 4997 int prop_size = map->unused_property_fields() - map->inobject_properties(); 4998 Object* properties; 4999 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, TENURED); 5000 if (!maybe_properties->ToObject(&properties)) return maybe_properties; 5001 } 5002 5003 // Reset the map for the object. 5004 object->set_map(constructor->initial_map()); 5005 5006 // Reinitialize the object from the constructor map. 5007 InitializeJSObjectFromMap(object, FixedArray::cast(properties), map); 5008 return object; 5009 } 5010 5011 5012 MaybeObject* Heap::AllocateStringFromOneByte(Vector<const uint8_t> string, 5013 PretenureFlag pretenure) { 5014 int length = string.length(); 5015 if (length == 1) { 5016 return Heap::LookupSingleCharacterStringFromCode(string[0]); 5017 } 5018 Object* result; 5019 { MaybeObject* maybe_result = 5020 AllocateRawOneByteString(string.length(), pretenure); 5021 if (!maybe_result->ToObject(&result)) return maybe_result; 5022 } 5023 5024 // Copy the characters into the new object. 5025 CopyChars(SeqOneByteString::cast(result)->GetChars(), 5026 string.start(), 5027 length); 5028 return result; 5029 } 5030 5031 5032 MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string, 5033 int non_ascii_start, 5034 PretenureFlag pretenure) { 5035 // Continue counting the number of characters in the UTF-8 string, starting 5036 // from the first non-ascii character or word. 5037 Access<UnicodeCache::Utf8Decoder> 5038 decoder(isolate_->unicode_cache()->utf8_decoder()); 5039 decoder->Reset(string.start() + non_ascii_start, 5040 string.length() - non_ascii_start); 5041 int utf16_length = decoder->Utf16Length(); 5042 ASSERT(utf16_length > 0); 5043 // Allocate string. 5044 Object* result; 5045 { 5046 int chars = non_ascii_start + utf16_length; 5047 MaybeObject* maybe_result = AllocateRawTwoByteString(chars, pretenure); 5048 if (!maybe_result->ToObject(&result)) return maybe_result; 5049 } 5050 // Convert and copy the characters into the new object. 5051 SeqTwoByteString* twobyte = SeqTwoByteString::cast(result); 5052 // Copy ascii portion. 5053 uint16_t* data = twobyte->GetChars(); 5054 if (non_ascii_start != 0) { 5055 const char* ascii_data = string.start(); 5056 for (int i = 0; i < non_ascii_start; i++) { 5057 *data++ = *ascii_data++; 5058 } 5059 } 5060 // Now write the remainder. 5061 decoder->WriteUtf16(data, utf16_length); 5062 return result; 5063 } 5064 5065 5066 MaybeObject* Heap::AllocateStringFromTwoByte(Vector<const uc16> string, 5067 PretenureFlag pretenure) { 5068 // Check if the string is an ASCII string. 5069 Object* result; 5070 int length = string.length(); 5071 const uc16* start = string.start(); 5072 5073 if (String::IsOneByte(start, length)) { 5074 MaybeObject* maybe_result = AllocateRawOneByteString(length, pretenure); 5075 if (!maybe_result->ToObject(&result)) return maybe_result; 5076 CopyChars(SeqOneByteString::cast(result)->GetChars(), start, length); 5077 } else { // It's not a one byte string. 5078 MaybeObject* maybe_result = AllocateRawTwoByteString(length, pretenure); 5079 if (!maybe_result->ToObject(&result)) return maybe_result; 5080 CopyChars(SeqTwoByteString::cast(result)->GetChars(), start, length); 5081 } 5082 return result; 5083 } 5084 5085 5086 Map* Heap::InternalizedStringMapForString(String* string) { 5087 // If the string is in new space it cannot be used as internalized. 5088 if (InNewSpace(string)) return NULL; 5089 5090 // Find the corresponding internalized string map for strings. 5091 switch (string->map()->instance_type()) { 5092 case STRING_TYPE: return internalized_string_map(); 5093 case ASCII_STRING_TYPE: return ascii_internalized_string_map(); 5094 case CONS_STRING_TYPE: return cons_internalized_string_map(); 5095 case CONS_ASCII_STRING_TYPE: return cons_ascii_internalized_string_map(); 5096 case EXTERNAL_STRING_TYPE: return external_internalized_string_map(); 5097 case EXTERNAL_ASCII_STRING_TYPE: 5098 return external_ascii_internalized_string_map(); 5099 case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: 5100 return external_internalized_string_with_one_byte_data_map(); 5101 case SHORT_EXTERNAL_STRING_TYPE: 5102 return short_external_internalized_string_map(); 5103 case SHORT_EXTERNAL_ASCII_STRING_TYPE: 5104 return short_external_ascii_internalized_string_map(); 5105 case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: 5106 return short_external_internalized_string_with_one_byte_data_map(); 5107 default: return NULL; // No match found. 5108 } 5109 } 5110 5111 5112 static inline void WriteOneByteData(Vector<const char> vector, 5113 uint8_t* chars, 5114 int len) { 5115 // Only works for ascii. 5116 ASSERT(vector.length() == len); 5117 OS::MemCopy(chars, vector.start(), len); 5118 } 5119 5120 static inline void WriteTwoByteData(Vector<const char> vector, 5121 uint16_t* chars, 5122 int len) { 5123 const uint8_t* stream = reinterpret_cast<const uint8_t*>(vector.start()); 5124 unsigned stream_length = vector.length(); 5125 while (stream_length != 0) { 5126 unsigned consumed = 0; 5127 uint32_t c = unibrow::Utf8::ValueOf(stream, stream_length, &consumed); 5128 ASSERT(c != unibrow::Utf8::kBadChar); 5129 ASSERT(consumed <= stream_length); 5130 stream_length -= consumed; 5131 stream += consumed; 5132 if (c > unibrow::Utf16::kMaxNonSurrogateCharCode) { 5133 len -= 2; 5134 if (len < 0) break; 5135 *chars++ = unibrow::Utf16::LeadSurrogate(c); 5136 *chars++ = unibrow::Utf16::TrailSurrogate(c); 5137 } else { 5138 len -= 1; 5139 if (len < 0) break; 5140 *chars++ = c; 5141 } 5142 } 5143 ASSERT(stream_length == 0); 5144 ASSERT(len == 0); 5145 } 5146 5147 5148 static inline void WriteOneByteData(String* s, uint8_t* chars, int len) { 5149 ASSERT(s->length() == len); 5150 String::WriteToFlat(s, chars, 0, len); 5151 } 5152 5153 5154 static inline void WriteTwoByteData(String* s, uint16_t* chars, int len) { 5155 ASSERT(s->length() == len); 5156 String::WriteToFlat(s, chars, 0, len); 5157 } 5158 5159 5160 template<bool is_one_byte, typename T> 5161 MaybeObject* Heap::AllocateInternalizedStringImpl( 5162 T t, int chars, uint32_t hash_field) { 5163 ASSERT(chars >= 0); 5164 // Compute map and object size. 5165 int size; 5166 Map* map; 5167 5168 if (is_one_byte) { 5169 if (chars > SeqOneByteString::kMaxLength) { 5170 return Failure::OutOfMemoryException(0x9); 5171 } 5172 map = ascii_internalized_string_map(); 5173 size = SeqOneByteString::SizeFor(chars); 5174 } else { 5175 if (chars > SeqTwoByteString::kMaxLength) { 5176 return Failure::OutOfMemoryException(0xa); 5177 } 5178 map = internalized_string_map(); 5179 size = SeqTwoByteString::SizeFor(chars); 5180 } 5181 AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, TENURED); 5182 5183 // Allocate string. 5184 Object* result; 5185 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE); 5186 if (!maybe_result->ToObject(&result)) return maybe_result; 5187 } 5188 5189 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(map); 5190 // Set length and hash fields of the allocated string. 5191 String* answer = String::cast(result); 5192 answer->set_length(chars); 5193 answer->set_hash_field(hash_field); 5194 5195 ASSERT_EQ(size, answer->Size()); 5196 5197 if (is_one_byte) { 5198 WriteOneByteData(t, SeqOneByteString::cast(answer)->GetChars(), chars); 5199 } else { 5200 WriteTwoByteData(t, SeqTwoByteString::cast(answer)->GetChars(), chars); 5201 } 5202 return answer; 5203 } 5204 5205 5206 // Need explicit instantiations. 5207 template 5208 MaybeObject* Heap::AllocateInternalizedStringImpl<true>(String*, int, uint32_t); 5209 template 5210 MaybeObject* Heap::AllocateInternalizedStringImpl<false>( 5211 String*, int, uint32_t); 5212 template 5213 MaybeObject* Heap::AllocateInternalizedStringImpl<false>( 5214 Vector<const char>, int, uint32_t); 5215 5216 5217 MaybeObject* Heap::AllocateRawOneByteString(int length, 5218 PretenureFlag pretenure) { 5219 if (length < 0 || length > SeqOneByteString::kMaxLength) { 5220 return Failure::OutOfMemoryException(0xb); 5221 } 5222 int size = SeqOneByteString::SizeFor(length); 5223 ASSERT(size <= SeqOneByteString::kMaxSize); 5224 AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); 5225 5226 Object* result; 5227 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE); 5228 if (!maybe_result->ToObject(&result)) return maybe_result; 5229 } 5230 5231 // Partially initialize the object. 5232 HeapObject::cast(result)->set_map_no_write_barrier(ascii_string_map()); 5233 String::cast(result)->set_length(length); 5234 String::cast(result)->set_hash_field(String::kEmptyHashField); 5235 ASSERT_EQ(size, HeapObject::cast(result)->Size()); 5236 5237 return result; 5238 } 5239 5240 5241 MaybeObject* Heap::AllocateRawTwoByteString(int length, 5242 PretenureFlag pretenure) { 5243 if (length < 0 || length > SeqTwoByteString::kMaxLength) { 5244 return Failure::OutOfMemoryException(0xc); 5245 } 5246 int size = SeqTwoByteString::SizeFor(length); 5247 ASSERT(size <= SeqTwoByteString::kMaxSize); 5248 AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); 5249 5250 Object* result; 5251 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE); 5252 if (!maybe_result->ToObject(&result)) return maybe_result; 5253 } 5254 5255 // Partially initialize the object. 5256 HeapObject::cast(result)->set_map_no_write_barrier(string_map()); 5257 String::cast(result)->set_length(length); 5258 String::cast(result)->set_hash_field(String::kEmptyHashField); 5259 ASSERT_EQ(size, HeapObject::cast(result)->Size()); 5260 return result; 5261 } 5262 5263 5264 MaybeObject* Heap::AllocateJSArray( 5265 ElementsKind elements_kind, 5266 PretenureFlag pretenure) { 5267 Context* native_context = isolate()->context()->native_context(); 5268 JSFunction* array_function = native_context->array_function(); 5269 Map* map = array_function->initial_map(); 5270 Map* transition_map = isolate()->get_initial_js_array_map(elements_kind); 5271 if (transition_map != NULL) map = transition_map; 5272 return AllocateJSObjectFromMap(map, pretenure); 5273 } 5274 5275 5276 MaybeObject* Heap::AllocateEmptyFixedArray() { 5277 int size = FixedArray::SizeFor(0); 5278 Object* result; 5279 { MaybeObject* maybe_result = 5280 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE); 5281 if (!maybe_result->ToObject(&result)) return maybe_result; 5282 } 5283 // Initialize the object. 5284 reinterpret_cast<FixedArray*>(result)->set_map_no_write_barrier( 5285 fixed_array_map()); 5286 reinterpret_cast<FixedArray*>(result)->set_length(0); 5287 return result; 5288 } 5289 5290 5291 MaybeObject* Heap::AllocateEmptyExternalArray(ExternalArrayType array_type) { 5292 return AllocateExternalArray(0, array_type, NULL, TENURED); 5293 } 5294 5295 5296 MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) { 5297 int len = src->length(); 5298 Object* obj; 5299 { MaybeObject* maybe_obj = AllocateRawFixedArray(len, NOT_TENURED); 5300 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 5301 } 5302 if (InNewSpace(obj)) { 5303 HeapObject* dst = HeapObject::cast(obj); 5304 dst->set_map_no_write_barrier(map); 5305 CopyBlock(dst->address() + kPointerSize, 5306 src->address() + kPointerSize, 5307 FixedArray::SizeFor(len) - kPointerSize); 5308 return obj; 5309 } 5310 HeapObject::cast(obj)->set_map_no_write_barrier(map); 5311 FixedArray* result = FixedArray::cast(obj); 5312 result->set_length(len); 5313 5314 // Copy the content 5315 DisallowHeapAllocation no_gc; 5316 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); 5317 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode); 5318 return result; 5319 } 5320 5321 5322 MaybeObject* Heap::CopyFixedDoubleArrayWithMap(FixedDoubleArray* src, 5323 Map* map) { 5324 int len = src->length(); 5325 Object* obj; 5326 { MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(len, NOT_TENURED); 5327 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 5328 } 5329 HeapObject* dst = HeapObject::cast(obj); 5330 dst->set_map_no_write_barrier(map); 5331 CopyBlock( 5332 dst->address() + FixedDoubleArray::kLengthOffset, 5333 src->address() + FixedDoubleArray::kLengthOffset, 5334 FixedDoubleArray::SizeFor(len) - FixedDoubleArray::kLengthOffset); 5335 return obj; 5336 } 5337 5338 5339 MaybeObject* Heap::CopyConstantPoolArrayWithMap(ConstantPoolArray* src, 5340 Map* map) { 5341 int int64_entries = src->count_of_int64_entries(); 5342 int ptr_entries = src->count_of_ptr_entries(); 5343 int int32_entries = src->count_of_int32_entries(); 5344 Object* obj; 5345 { MaybeObject* maybe_obj = 5346 AllocateConstantPoolArray(int64_entries, ptr_entries, int32_entries); 5347 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 5348 } 5349 HeapObject* dst = HeapObject::cast(obj); 5350 dst->set_map_no_write_barrier(map); 5351 CopyBlock( 5352 dst->address() + ConstantPoolArray::kLengthOffset, 5353 src->address() + ConstantPoolArray::kLengthOffset, 5354 ConstantPoolArray::SizeFor(int64_entries, ptr_entries, int32_entries) 5355 - ConstantPoolArray::kLengthOffset); 5356 return obj; 5357 } 5358 5359 5360 MaybeObject* Heap::AllocateRawFixedArray(int length, PretenureFlag pretenure) { 5361 if (length < 0 || length > FixedArray::kMaxLength) { 5362 return Failure::OutOfMemoryException(0xe); 5363 } 5364 int size = FixedArray::SizeFor(length); 5365 AllocationSpace space = SelectSpace(size, OLD_POINTER_SPACE, pretenure); 5366 5367 return AllocateRaw(size, space, OLD_POINTER_SPACE); 5368 } 5369 5370 5371 MaybeObject* Heap::AllocateFixedArrayWithFiller(int length, 5372 PretenureFlag pretenure, 5373 Object* filler) { 5374 ASSERT(length >= 0); 5375 ASSERT(empty_fixed_array()->IsFixedArray()); 5376 if (length == 0) return empty_fixed_array(); 5377 5378 ASSERT(!InNewSpace(filler)); 5379 Object* result; 5380 { MaybeObject* maybe_result = AllocateRawFixedArray(length, pretenure); 5381 if (!maybe_result->ToObject(&result)) return maybe_result; 5382 } 5383 5384 HeapObject::cast(result)->set_map_no_write_barrier(fixed_array_map()); 5385 FixedArray* array = FixedArray::cast(result); 5386 array->set_length(length); 5387 MemsetPointer(array->data_start(), filler, length); 5388 return array; 5389 } 5390 5391 5392 MaybeObject* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) { 5393 return AllocateFixedArrayWithFiller(length, pretenure, undefined_value()); 5394 } 5395 5396 5397 MaybeObject* Heap::AllocateFixedArrayWithHoles(int length, 5398 PretenureFlag pretenure) { 5399 return AllocateFixedArrayWithFiller(length, pretenure, the_hole_value()); 5400 } 5401 5402 5403 MaybeObject* Heap::AllocateUninitializedFixedArray(int length) { 5404 if (length == 0) return empty_fixed_array(); 5405 5406 Object* obj; 5407 { MaybeObject* maybe_obj = AllocateRawFixedArray(length, NOT_TENURED); 5408 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 5409 } 5410 5411 reinterpret_cast<FixedArray*>(obj)->set_map_no_write_barrier( 5412 fixed_array_map()); 5413 FixedArray::cast(obj)->set_length(length); 5414 return obj; 5415 } 5416 5417 5418 MaybeObject* Heap::AllocateEmptyFixedDoubleArray() { 5419 int size = FixedDoubleArray::SizeFor(0); 5420 Object* result; 5421 { MaybeObject* maybe_result = 5422 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE); 5423 if (!maybe_result->ToObject(&result)) return maybe_result; 5424 } 5425 // Initialize the object. 5426 reinterpret_cast<FixedDoubleArray*>(result)->set_map_no_write_barrier( 5427 fixed_double_array_map()); 5428 reinterpret_cast<FixedDoubleArray*>(result)->set_length(0); 5429 return result; 5430 } 5431 5432 5433 MaybeObject* Heap::AllocateUninitializedFixedDoubleArray( 5434 int length, 5435 PretenureFlag pretenure) { 5436 if (length == 0) return empty_fixed_array(); 5437 5438 Object* elements_object; 5439 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure); 5440 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj; 5441 FixedDoubleArray* elements = 5442 reinterpret_cast<FixedDoubleArray*>(elements_object); 5443 5444 elements->set_map_no_write_barrier(fixed_double_array_map()); 5445 elements->set_length(length); 5446 return elements; 5447 } 5448 5449 5450 MaybeObject* Heap::AllocateFixedDoubleArrayWithHoles( 5451 int length, 5452 PretenureFlag pretenure) { 5453 if (length == 0) return empty_fixed_array(); 5454 5455 Object* elements_object; 5456 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure); 5457 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj; 5458 FixedDoubleArray* elements = 5459 reinterpret_cast<FixedDoubleArray*>(elements_object); 5460 5461 for (int i = 0; i < length; ++i) { 5462 elements->set_the_hole(i); 5463 } 5464 5465 elements->set_map_no_write_barrier(fixed_double_array_map()); 5466 elements->set_length(length); 5467 return elements; 5468 } 5469 5470 5471 MaybeObject* Heap::AllocateRawFixedDoubleArray(int length, 5472 PretenureFlag pretenure) { 5473 if (length < 0 || length > FixedDoubleArray::kMaxLength) { 5474 return Failure::OutOfMemoryException(0xf); 5475 } 5476 int size = FixedDoubleArray::SizeFor(length); 5477 #ifndef V8_HOST_ARCH_64_BIT 5478 size += kPointerSize; 5479 #endif 5480 AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure); 5481 5482 HeapObject* object; 5483 { MaybeObject* maybe_object = AllocateRaw(size, space, OLD_DATA_SPACE); 5484 if (!maybe_object->To<HeapObject>(&object)) return maybe_object; 5485 } 5486 5487 return EnsureDoubleAligned(this, object, size); 5488 } 5489 5490 5491 MaybeObject* Heap::AllocateConstantPoolArray(int number_of_int64_entries, 5492 int number_of_ptr_entries, 5493 int number_of_int32_entries) { 5494 ASSERT(number_of_int64_entries > 0 || number_of_ptr_entries > 0 || 5495 number_of_int32_entries > 0); 5496 int size = ConstantPoolArray::SizeFor(number_of_int64_entries, 5497 number_of_ptr_entries, 5498 number_of_int32_entries); 5499 #ifndef V8_HOST_ARCH_64_BIT 5500 size += kPointerSize; 5501 #endif 5502 AllocationSpace space = SelectSpace(size, OLD_POINTER_SPACE, TENURED); 5503 5504 HeapObject* object; 5505 { MaybeObject* maybe_object = AllocateRaw(size, space, OLD_POINTER_SPACE); 5506 if (!maybe_object->To<HeapObject>(&object)) return maybe_object; 5507 } 5508 object = EnsureDoubleAligned(this, object, size); 5509 HeapObject::cast(object)->set_map_no_write_barrier(constant_pool_array_map()); 5510 5511 ConstantPoolArray* constant_pool = 5512 reinterpret_cast<ConstantPoolArray*>(object); 5513 constant_pool->SetEntryCounts(number_of_int64_entries, 5514 number_of_ptr_entries, 5515 number_of_int32_entries); 5516 MemsetPointer( 5517 HeapObject::RawField( 5518 constant_pool, 5519 constant_pool->OffsetOfElementAt(constant_pool->first_ptr_index())), 5520 undefined_value(), 5521 number_of_ptr_entries); 5522 return constant_pool; 5523 } 5524 5525 5526 MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) { 5527 Object* result; 5528 { MaybeObject* maybe_result = AllocateFixedArray(length, pretenure); 5529 if (!maybe_result->ToObject(&result)) return maybe_result; 5530 } 5531 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier( 5532 hash_table_map()); 5533 ASSERT(result->IsHashTable()); 5534 return result; 5535 } 5536 5537 5538 MaybeObject* Heap::AllocateSymbol() { 5539 // Statically ensure that it is safe to allocate symbols in paged spaces. 5540 STATIC_ASSERT(Symbol::kSize <= Page::kNonCodeObjectAreaSize); 5541 5542 Object* result; 5543 MaybeObject* maybe = 5544 AllocateRaw(Symbol::kSize, OLD_POINTER_SPACE, OLD_POINTER_SPACE); 5545 if (!maybe->ToObject(&result)) return maybe; 5546 5547 HeapObject::cast(result)->set_map_no_write_barrier(symbol_map()); 5548 5549 // Generate a random hash value. 5550 int hash; 5551 int attempts = 0; 5552 do { 5553 hash = isolate()->random_number_generator()->NextInt() & Name::kHashBitMask; 5554 attempts++; 5555 } while (hash == 0 && attempts < 30); 5556 if (hash == 0) hash = 1; // never return 0 5557 5558 Symbol::cast(result)->set_hash_field( 5559 Name::kIsNotArrayIndexMask | (hash << Name::kHashShift)); 5560 Symbol::cast(result)->set_name(undefined_value()); 5561 Symbol::cast(result)->set_flags(Smi::FromInt(0)); 5562 5563 ASSERT(!Symbol::cast(result)->is_private()); 5564 return result; 5565 } 5566 5567 5568 MaybeObject* Heap::AllocatePrivateSymbol() { 5569 MaybeObject* maybe = AllocateSymbol(); 5570 Symbol* symbol; 5571 if (!maybe->To(&symbol)) return maybe; 5572 symbol->set_is_private(true); 5573 return symbol; 5574 } 5575 5576 5577 MaybeObject* Heap::AllocateNativeContext() { 5578 Object* result; 5579 { MaybeObject* maybe_result = 5580 AllocateFixedArray(Context::NATIVE_CONTEXT_SLOTS); 5581 if (!maybe_result->ToObject(&result)) return maybe_result; 5582 } 5583 Context* context = reinterpret_cast<Context*>(result); 5584 context->set_map_no_write_barrier(native_context_map()); 5585 context->set_js_array_maps(undefined_value()); 5586 ASSERT(context->IsNativeContext()); 5587 ASSERT(result->IsContext()); 5588 return result; 5589 } 5590 5591 5592 MaybeObject* Heap::AllocateGlobalContext(JSFunction* function, 5593 ScopeInfo* scope_info) { 5594 Object* result; 5595 { MaybeObject* maybe_result = 5596 AllocateFixedArray(scope_info->ContextLength(), TENURED); 5597 if (!maybe_result->ToObject(&result)) return maybe_result; 5598 } 5599 Context* context = reinterpret_cast<Context*>(result); 5600 context->set_map_no_write_barrier(global_context_map()); 5601 context->set_closure(function); 5602 context->set_previous(function->context()); 5603 context->set_extension(scope_info); 5604 context->set_global_object(function->context()->global_object()); 5605 ASSERT(context->IsGlobalContext()); 5606 ASSERT(result->IsContext()); 5607 return context; 5608 } 5609 5610 5611 MaybeObject* Heap::AllocateModuleContext(ScopeInfo* scope_info) { 5612 Object* result; 5613 { MaybeObject* maybe_result = 5614 AllocateFixedArray(scope_info->ContextLength(), TENURED); 5615 if (!maybe_result->ToObject(&result)) return maybe_result; 5616 } 5617 Context* context = reinterpret_cast<Context*>(result); 5618 context->set_map_no_write_barrier(module_context_map()); 5619 // Instance link will be set later. 5620 context->set_extension(Smi::FromInt(0)); 5621 return context; 5622 } 5623 5624 5625 MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) { 5626 ASSERT(length >= Context::MIN_CONTEXT_SLOTS); 5627 Object* result; 5628 { MaybeObject* maybe_result = AllocateFixedArray(length); 5629 if (!maybe_result->ToObject(&result)) return maybe_result; 5630 } 5631 Context* context = reinterpret_cast<Context*>(result); 5632 context->set_map_no_write_barrier(function_context_map()); 5633 context->set_closure(function); 5634 context->set_previous(function->context()); 5635 context->set_extension(Smi::FromInt(0)); 5636 context->set_global_object(function->context()->global_object()); 5637 return context; 5638 } 5639 5640 5641 MaybeObject* Heap::AllocateCatchContext(JSFunction* function, 5642 Context* previous, 5643 String* name, 5644 Object* thrown_object) { 5645 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX); 5646 Object* result; 5647 { MaybeObject* maybe_result = 5648 AllocateFixedArray(Context::MIN_CONTEXT_SLOTS + 1); 5649 if (!maybe_result->ToObject(&result)) return maybe_result; 5650 } 5651 Context* context = reinterpret_cast<Context*>(result); 5652 context->set_map_no_write_barrier(catch_context_map()); 5653 context->set_closure(function); 5654 context->set_previous(previous); 5655 context->set_extension(name); 5656 context->set_global_object(previous->global_object()); 5657 context->set(Context::THROWN_OBJECT_INDEX, thrown_object); 5658 return context; 5659 } 5660 5661 5662 MaybeObject* Heap::AllocateWithContext(JSFunction* function, 5663 Context* previous, 5664 JSReceiver* extension) { 5665 Object* result; 5666 { MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS); 5667 if (!maybe_result->ToObject(&result)) return maybe_result; 5668 } 5669 Context* context = reinterpret_cast<Context*>(result); 5670 context->set_map_no_write_barrier(with_context_map()); 5671 context->set_closure(function); 5672 context->set_previous(previous); 5673 context->set_extension(extension); 5674 context->set_global_object(previous->global_object()); 5675 return context; 5676 } 5677 5678 5679 MaybeObject* Heap::AllocateBlockContext(JSFunction* function, 5680 Context* previous, 5681 ScopeInfo* scope_info) { 5682 Object* result; 5683 { MaybeObject* maybe_result = 5684 AllocateFixedArrayWithHoles(scope_info->ContextLength()); 5685 if (!maybe_result->ToObject(&result)) return maybe_result; 5686 } 5687 Context* context = reinterpret_cast<Context*>(result); 5688 context->set_map_no_write_barrier(block_context_map()); 5689 context->set_closure(function); 5690 context->set_previous(previous); 5691 context->set_extension(scope_info); 5692 context->set_global_object(previous->global_object()); 5693 return context; 5694 } 5695 5696 5697 MaybeObject* Heap::AllocateScopeInfo(int length) { 5698 FixedArray* scope_info; 5699 MaybeObject* maybe_scope_info = AllocateFixedArray(length, TENURED); 5700 if (!maybe_scope_info->To(&scope_info)) return maybe_scope_info; 5701 scope_info->set_map_no_write_barrier(scope_info_map()); 5702 return scope_info; 5703 } 5704 5705 5706 MaybeObject* Heap::AllocateExternal(void* value) { 5707 Foreign* foreign; 5708 { MaybeObject* maybe_result = AllocateForeign(static_cast<Address>(value)); 5709 if (!maybe_result->To(&foreign)) return maybe_result; 5710 } 5711 JSObject* external; 5712 { MaybeObject* maybe_result = AllocateJSObjectFromMap(external_map()); 5713 if (!maybe_result->To(&external)) return maybe_result; 5714 } 5715 external->SetInternalField(0, foreign); 5716 return external; 5717 } 5718 5719 5720 MaybeObject* Heap::AllocateStruct(InstanceType type) { 5721 Map* map; 5722 switch (type) { 5723 #define MAKE_CASE(NAME, Name, name) \ 5724 case NAME##_TYPE: map = name##_map(); break; 5725 STRUCT_LIST(MAKE_CASE) 5726 #undef MAKE_CASE 5727 default: 5728 UNREACHABLE(); 5729 return Failure::InternalError(); 5730 } 5731 int size = map->instance_size(); 5732 AllocationSpace space = SelectSpace(size, OLD_POINTER_SPACE, TENURED); 5733 Object* result; 5734 { MaybeObject* maybe_result = Allocate(map, space); 5735 if (!maybe_result->ToObject(&result)) return maybe_result; 5736 } 5737 Struct::cast(result)->InitializeBody(size); 5738 return result; 5739 } 5740 5741 5742 bool Heap::IsHeapIterable() { 5743 return (!old_pointer_space()->was_swept_conservatively() && 5744 !old_data_space()->was_swept_conservatively()); 5745 } 5746 5747 5748 void Heap::EnsureHeapIsIterable() { 5749 ASSERT(AllowHeapAllocation::IsAllowed()); 5750 if (!IsHeapIterable()) { 5751 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable"); 5752 } 5753 ASSERT(IsHeapIterable()); 5754 } 5755 5756 5757 void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) { 5758 incremental_marking()->Step(step_size, 5759 IncrementalMarking::NO_GC_VIA_STACK_GUARD); 5760 5761 if (incremental_marking()->IsComplete()) { 5762 bool uncommit = false; 5763 if (gc_count_at_last_idle_gc_ == gc_count_) { 5764 // No GC since the last full GC, the mutator is probably not active. 5765 isolate_->compilation_cache()->Clear(); 5766 uncommit = true; 5767 } 5768 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental"); 5769 mark_sweeps_since_idle_round_started_++; 5770 gc_count_at_last_idle_gc_ = gc_count_; 5771 if (uncommit) { 5772 new_space_.Shrink(); 5773 UncommitFromSpace(); 5774 } 5775 } 5776 } 5777 5778 5779 bool Heap::IdleNotification(int hint) { 5780 // Hints greater than this value indicate that 5781 // the embedder is requesting a lot of GC work. 5782 const int kMaxHint = 1000; 5783 const int kMinHintForIncrementalMarking = 10; 5784 // Minimal hint that allows to do full GC. 5785 const int kMinHintForFullGC = 100; 5786 intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4; 5787 // The size factor is in range [5..250]. The numbers here are chosen from 5788 // experiments. If you changes them, make sure to test with 5789 // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.* 5790 intptr_t step_size = 5791 size_factor * IncrementalMarking::kAllocatedThreshold; 5792 5793 if (contexts_disposed_ > 0) { 5794 contexts_disposed_ = 0; 5795 int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000); 5796 if (hint >= mark_sweep_time && !FLAG_expose_gc && 5797 incremental_marking()->IsStopped()) { 5798 HistogramTimerScope scope(isolate_->counters()->gc_context()); 5799 CollectAllGarbage(kReduceMemoryFootprintMask, 5800 "idle notification: contexts disposed"); 5801 } else { 5802 AdvanceIdleIncrementalMarking(step_size); 5803 } 5804 5805 // After context disposal there is likely a lot of garbage remaining, reset 5806 // the idle notification counters in order to trigger more incremental GCs 5807 // on subsequent idle notifications. 5808 StartIdleRound(); 5809 return false; 5810 } 5811 5812 if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) { 5813 return IdleGlobalGC(); 5814 } 5815 5816 // By doing small chunks of GC work in each IdleNotification, 5817 // perform a round of incremental GCs and after that wait until 5818 // the mutator creates enough garbage to justify a new round. 5819 // An incremental GC progresses as follows: 5820 // 1. many incremental marking steps, 5821 // 2. one old space mark-sweep-compact, 5822 // 3. many lazy sweep steps. 5823 // Use mark-sweep-compact events to count incremental GCs in a round. 5824 5825 if (incremental_marking()->IsStopped()) { 5826 if (!mark_compact_collector()->AreSweeperThreadsActivated() && 5827 !IsSweepingComplete() && 5828 !AdvanceSweepers(static_cast<int>(step_size))) { 5829 return false; 5830 } 5831 } 5832 5833 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) { 5834 if (EnoughGarbageSinceLastIdleRound()) { 5835 StartIdleRound(); 5836 } else { 5837 return true; 5838 } 5839 } 5840 5841 int remaining_mark_sweeps = kMaxMarkSweepsInIdleRound - 5842 mark_sweeps_since_idle_round_started_; 5843 5844 if (incremental_marking()->IsStopped()) { 5845 // If there are no more than two GCs left in this idle round and we are 5846 // allowed to do a full GC, then make those GCs full in order to compact 5847 // the code space. 5848 // TODO(ulan): Once we enable code compaction for incremental marking, 5849 // we can get rid of this special case and always start incremental marking. 5850 if (remaining_mark_sweeps <= 2 && hint >= kMinHintForFullGC) { 5851 CollectAllGarbage(kReduceMemoryFootprintMask, 5852 "idle notification: finalize idle round"); 5853 mark_sweeps_since_idle_round_started_++; 5854 } else if (hint > kMinHintForIncrementalMarking) { 5855 incremental_marking()->Start(); 5856 } 5857 } 5858 if (!incremental_marking()->IsStopped() && 5859 hint > kMinHintForIncrementalMarking) { 5860 AdvanceIdleIncrementalMarking(step_size); 5861 } 5862 5863 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) { 5864 FinishIdleRound(); 5865 return true; 5866 } 5867 5868 return false; 5869 } 5870 5871 5872 bool Heap::IdleGlobalGC() { 5873 static const int kIdlesBeforeScavenge = 4; 5874 static const int kIdlesBeforeMarkSweep = 7; 5875 static const int kIdlesBeforeMarkCompact = 8; 5876 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1; 5877 static const unsigned int kGCsBetweenCleanup = 4; 5878 5879 if (!last_idle_notification_gc_count_init_) { 5880 last_idle_notification_gc_count_ = gc_count_; 5881 last_idle_notification_gc_count_init_ = true; 5882 } 5883 5884 bool uncommit = true; 5885 bool finished = false; 5886 5887 // Reset the number of idle notifications received when a number of 5888 // GCs have taken place. This allows another round of cleanup based 5889 // on idle notifications if enough work has been carried out to 5890 // provoke a number of garbage collections. 5891 if (gc_count_ - last_idle_notification_gc_count_ < kGCsBetweenCleanup) { 5892 number_idle_notifications_ = 5893 Min(number_idle_notifications_ + 1, kMaxIdleCount); 5894 } else { 5895 number_idle_notifications_ = 0; 5896 last_idle_notification_gc_count_ = gc_count_; 5897 } 5898 5899 if (number_idle_notifications_ == kIdlesBeforeScavenge) { 5900 CollectGarbage(NEW_SPACE, "idle notification"); 5901 new_space_.Shrink(); 5902 last_idle_notification_gc_count_ = gc_count_; 5903 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) { 5904 // Before doing the mark-sweep collections we clear the 5905 // compilation cache to avoid hanging on to source code and 5906 // generated code for cached functions. 5907 isolate_->compilation_cache()->Clear(); 5908 5909 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification"); 5910 new_space_.Shrink(); 5911 last_idle_notification_gc_count_ = gc_count_; 5912 5913 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { 5914 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification"); 5915 new_space_.Shrink(); 5916 last_idle_notification_gc_count_ = gc_count_; 5917 number_idle_notifications_ = 0; 5918 finished = true; 5919 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) { 5920 // If we have received more than kIdlesBeforeMarkCompact idle 5921 // notifications we do not perform any cleanup because we don't 5922 // expect to gain much by doing so. 5923 finished = true; 5924 } 5925 5926 if (uncommit) UncommitFromSpace(); 5927 5928 return finished; 5929 } 5930 5931 5932 #ifdef DEBUG 5933 5934 void Heap::Print() { 5935 if (!HasBeenSetUp()) return; 5936 isolate()->PrintStack(stdout); 5937 AllSpaces spaces(this); 5938 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { 5939 space->Print(); 5940 } 5941 } 5942 5943 5944 void Heap::ReportCodeStatistics(const char* title) { 5945 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title); 5946 PagedSpace::ResetCodeStatistics(isolate()); 5947 // We do not look for code in new space, map space, or old space. If code 5948 // somehow ends up in those spaces, we would miss it here. 5949 code_space_->CollectCodeStatistics(); 5950 lo_space_->CollectCodeStatistics(); 5951 PagedSpace::ReportCodeStatistics(isolate()); 5952 } 5953 5954 5955 // This function expects that NewSpace's allocated objects histogram is 5956 // populated (via a call to CollectStatistics or else as a side effect of a 5957 // just-completed scavenge collection). 5958 void Heap::ReportHeapStatistics(const char* title) { 5959 USE(title); 5960 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n", 5961 title, gc_count_); 5962 PrintF("old_generation_allocation_limit_ %" V8_PTR_PREFIX "d\n", 5963 old_generation_allocation_limit_); 5964 5965 PrintF("\n"); 5966 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles(isolate_)); 5967 isolate_->global_handles()->PrintStats(); 5968 PrintF("\n"); 5969 5970 PrintF("Heap statistics : "); 5971 isolate_->memory_allocator()->ReportStatistics(); 5972 PrintF("To space : "); 5973 new_space_.ReportStatistics(); 5974 PrintF("Old pointer space : "); 5975 old_pointer_space_->ReportStatistics(); 5976 PrintF("Old data space : "); 5977 old_data_space_->ReportStatistics(); 5978 PrintF("Code space : "); 5979 code_space_->ReportStatistics(); 5980 PrintF("Map space : "); 5981 map_space_->ReportStatistics(); 5982 PrintF("Cell space : "); 5983 cell_space_->ReportStatistics(); 5984 PrintF("PropertyCell space : "); 5985 property_cell_space_->ReportStatistics(); 5986 PrintF("Large object space : "); 5987 lo_space_->ReportStatistics(); 5988 PrintF(">>>>>> ========================================= >>>>>>\n"); 5989 } 5990 5991 #endif // DEBUG 5992 5993 bool Heap::Contains(HeapObject* value) { 5994 return Contains(value->address()); 5995 } 5996 5997 5998 bool Heap::Contains(Address addr) { 5999 if (isolate_->memory_allocator()->IsOutsideAllocatedSpace(addr)) return false; 6000 return HasBeenSetUp() && 6001 (new_space_.ToSpaceContains(addr) || 6002 old_pointer_space_->Contains(addr) || 6003 old_data_space_->Contains(addr) || 6004 code_space_->Contains(addr) || 6005 map_space_->Contains(addr) || 6006 cell_space_->Contains(addr) || 6007 property_cell_space_->Contains(addr) || 6008 lo_space_->SlowContains(addr)); 6009 } 6010 6011 6012 bool Heap::InSpace(HeapObject* value, AllocationSpace space) { 6013 return InSpace(value->address(), space); 6014 } 6015 6016 6017 bool Heap::InSpace(Address addr, AllocationSpace space) { 6018 if (isolate_->memory_allocator()->IsOutsideAllocatedSpace(addr)) return false; 6019 if (!HasBeenSetUp()) return false; 6020 6021 switch (space) { 6022 case NEW_SPACE: 6023 return new_space_.ToSpaceContains(addr); 6024 case OLD_POINTER_SPACE: 6025 return old_pointer_space_->Contains(addr); 6026 case OLD_DATA_SPACE: 6027 return old_data_space_->Contains(addr); 6028 case CODE_SPACE: 6029 return code_space_->Contains(addr); 6030 case MAP_SPACE: 6031 return map_space_->Contains(addr); 6032 case CELL_SPACE: 6033 return cell_space_->Contains(addr); 6034 case PROPERTY_CELL_SPACE: 6035 return property_cell_space_->Contains(addr); 6036 case LO_SPACE: 6037 return lo_space_->SlowContains(addr); 6038 } 6039 6040 return false; 6041 } 6042 6043 6044 #ifdef VERIFY_HEAP 6045 void Heap::Verify() { 6046 CHECK(HasBeenSetUp()); 6047 6048 store_buffer()->Verify(); 6049 6050 VerifyPointersVisitor visitor; 6051 IterateRoots(&visitor, VISIT_ONLY_STRONG); 6052 6053 new_space_.Verify(); 6054 6055 old_pointer_space_->Verify(&visitor); 6056 map_space_->Verify(&visitor); 6057 6058 VerifyPointersVisitor no_dirty_regions_visitor; 6059 old_data_space_->Verify(&no_dirty_regions_visitor); 6060 code_space_->Verify(&no_dirty_regions_visitor); 6061 cell_space_->Verify(&no_dirty_regions_visitor); 6062 property_cell_space_->Verify(&no_dirty_regions_visitor); 6063 6064 lo_space_->Verify(); 6065 } 6066 #endif 6067 6068 6069 MaybeObject* Heap::InternalizeUtf8String(Vector<const char> string) { 6070 Object* result = NULL; 6071 Object* new_table; 6072 { MaybeObject* maybe_new_table = 6073 string_table()->LookupUtf8String(string, &result); 6074 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table; 6075 } 6076 // Can't use set_string_table because StringTable::cast knows that 6077 // StringTable is a singleton and checks for identity. 6078 roots_[kStringTableRootIndex] = new_table; 6079 ASSERT(result != NULL); 6080 return result; 6081 } 6082 6083 6084 MaybeObject* Heap::InternalizeOneByteString(Vector<const uint8_t> string) { 6085 Object* result = NULL; 6086 Object* new_table; 6087 { MaybeObject* maybe_new_table = 6088 string_table()->LookupOneByteString(string, &result); 6089 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table; 6090 } 6091 // Can't use set_string_table because StringTable::cast knows that 6092 // StringTable is a singleton and checks for identity. 6093 roots_[kStringTableRootIndex] = new_table; 6094 ASSERT(result != NULL); 6095 return result; 6096 } 6097 6098 6099 MaybeObject* Heap::InternalizeOneByteString(Handle<SeqOneByteString> string, 6100 int from, 6101 int length) { 6102 Object* result = NULL; 6103 Object* new_table; 6104 { MaybeObject* maybe_new_table = 6105 string_table()->LookupSubStringOneByteString(string, 6106 from, 6107 length, 6108 &result); 6109 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table; 6110 } 6111 // Can't use set_string_table because StringTable::cast knows that 6112 // StringTable is a singleton and checks for identity. 6113 roots_[kStringTableRootIndex] = new_table; 6114 ASSERT(result != NULL); 6115 return result; 6116 } 6117 6118 6119 MaybeObject* Heap::InternalizeTwoByteString(Vector<const uc16> string) { 6120 Object* result = NULL; 6121 Object* new_table; 6122 { MaybeObject* maybe_new_table = 6123 string_table()->LookupTwoByteString(string, &result); 6124 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table; 6125 } 6126 // Can't use set_string_table because StringTable::cast knows that 6127 // StringTable is a singleton and checks for identity. 6128 roots_[kStringTableRootIndex] = new_table; 6129 ASSERT(result != NULL); 6130 return result; 6131 } 6132 6133 6134 MaybeObject* Heap::InternalizeString(String* string) { 6135 if (string->IsInternalizedString()) return string; 6136 Object* result = NULL; 6137 Object* new_table; 6138 { MaybeObject* maybe_new_table = 6139 string_table()->LookupString(string, &result); 6140 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table; 6141 } 6142 // Can't use set_string_table because StringTable::cast knows that 6143 // StringTable is a singleton and checks for identity. 6144 roots_[kStringTableRootIndex] = new_table; 6145 ASSERT(result != NULL); 6146 return result; 6147 } 6148 6149 6150 bool Heap::InternalizeStringIfExists(String* string, String** result) { 6151 if (string->IsInternalizedString()) { 6152 *result = string; 6153 return true; 6154 } 6155 return string_table()->LookupStringIfExists(string, result); 6156 } 6157 6158 6159 void Heap::ZapFromSpace() { 6160 NewSpacePageIterator it(new_space_.FromSpaceStart(), 6161 new_space_.FromSpaceEnd()); 6162 while (it.has_next()) { 6163 NewSpacePage* page = it.next(); 6164 for (Address cursor = page->area_start(), limit = page->area_end(); 6165 cursor < limit; 6166 cursor += kPointerSize) { 6167 Memory::Address_at(cursor) = kFromSpaceZapValue; 6168 } 6169 } 6170 } 6171 6172 6173 void Heap::IterateAndMarkPointersToFromSpace(Address start, 6174 Address end, 6175 ObjectSlotCallback callback) { 6176 Address slot_address = start; 6177 6178 // We are not collecting slots on new space objects during mutation 6179 // thus we have to scan for pointers to evacuation candidates when we 6180 // promote objects. But we should not record any slots in non-black 6181 // objects. Grey object's slots would be rescanned. 6182 // White object might not survive until the end of collection 6183 // it would be a violation of the invariant to record it's slots. 6184 bool record_slots = false; 6185 if (incremental_marking()->IsCompacting()) { 6186 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::FromAddress(start)); 6187 record_slots = Marking::IsBlack(mark_bit); 6188 } 6189 6190 while (slot_address < end) { 6191 Object** slot = reinterpret_cast<Object**>(slot_address); 6192 Object* object = *slot; 6193 // If the store buffer becomes overfull we mark pages as being exempt from 6194 // the store buffer. These pages are scanned to find pointers that point 6195 // to the new space. In that case we may hit newly promoted objects and 6196 // fix the pointers before the promotion queue gets to them. Thus the 'if'. 6197 if (object->IsHeapObject()) { 6198 if (Heap::InFromSpace(object)) { 6199 callback(reinterpret_cast<HeapObject**>(slot), 6200 HeapObject::cast(object)); 6201 Object* new_object = *slot; 6202 if (InNewSpace(new_object)) { 6203 SLOW_ASSERT(Heap::InToSpace(new_object)); 6204 SLOW_ASSERT(new_object->IsHeapObject()); 6205 store_buffer_.EnterDirectlyIntoStoreBuffer( 6206 reinterpret_cast<Address>(slot)); 6207 } 6208 SLOW_ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object)); 6209 } else if (record_slots && 6210 MarkCompactCollector::IsOnEvacuationCandidate(object)) { 6211 mark_compact_collector()->RecordSlot(slot, slot, object); 6212 } 6213 } 6214 slot_address += kPointerSize; 6215 } 6216 } 6217 6218 6219 #ifdef DEBUG 6220 typedef bool (*CheckStoreBufferFilter)(Object** addr); 6221 6222 6223 bool IsAMapPointerAddress(Object** addr) { 6224 uintptr_t a = reinterpret_cast<uintptr_t>(addr); 6225 int mod = a % Map::kSize; 6226 return mod >= Map::kPointerFieldsBeginOffset && 6227 mod < Map::kPointerFieldsEndOffset; 6228 } 6229 6230 6231 bool EverythingsAPointer(Object** addr) { 6232 return true; 6233 } 6234 6235 6236 static void CheckStoreBuffer(Heap* heap, 6237 Object** current, 6238 Object** limit, 6239 Object**** store_buffer_position, 6240 Object*** store_buffer_top, 6241 CheckStoreBufferFilter filter, 6242 Address special_garbage_start, 6243 Address special_garbage_end) { 6244 Map* free_space_map = heap->free_space_map(); 6245 for ( ; current < limit; current++) { 6246 Object* o = *current; 6247 Address current_address = reinterpret_cast<Address>(current); 6248 // Skip free space. 6249 if (o == free_space_map) { 6250 Address current_address = reinterpret_cast<Address>(current); 6251 FreeSpace* free_space = 6252 FreeSpace::cast(HeapObject::FromAddress(current_address)); 6253 int skip = free_space->Size(); 6254 ASSERT(current_address + skip <= reinterpret_cast<Address>(limit)); 6255 ASSERT(skip > 0); 6256 current_address += skip - kPointerSize; 6257 current = reinterpret_cast<Object**>(current_address); 6258 continue; 6259 } 6260 // Skip the current linear allocation space between top and limit which is 6261 // unmarked with the free space map, but can contain junk. 6262 if (current_address == special_garbage_start && 6263 special_garbage_end != special_garbage_start) { 6264 current_address = special_garbage_end - kPointerSize; 6265 current = reinterpret_cast<Object**>(current_address); 6266 continue; 6267 } 6268 if (!(*filter)(current)) continue; 6269 ASSERT(current_address < special_garbage_start || 6270 current_address >= special_garbage_end); 6271 ASSERT(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue); 6272 // We have to check that the pointer does not point into new space 6273 // without trying to cast it to a heap object since the hash field of 6274 // a string can contain values like 1 and 3 which are tagged null 6275 // pointers. 6276 if (!heap->InNewSpace(o)) continue; 6277 while (**store_buffer_position < current && 6278 *store_buffer_position < store_buffer_top) { 6279 (*store_buffer_position)++; 6280 } 6281 if (**store_buffer_position != current || 6282 *store_buffer_position == store_buffer_top) { 6283 Object** obj_start = current; 6284 while (!(*obj_start)->IsMap()) obj_start--; 6285 UNREACHABLE(); 6286 } 6287 } 6288 } 6289 6290 6291 // Check that the store buffer contains all intergenerational pointers by 6292 // scanning a page and ensuring that all pointers to young space are in the 6293 // store buffer. 6294 void Heap::OldPointerSpaceCheckStoreBuffer() { 6295 OldSpace* space = old_pointer_space(); 6296 PageIterator pages(space); 6297 6298 store_buffer()->SortUniq(); 6299 6300 while (pages.has_next()) { 6301 Page* page = pages.next(); 6302 Object** current = reinterpret_cast<Object**>(page->area_start()); 6303 6304 Address end = page->area_end(); 6305 6306 Object*** store_buffer_position = store_buffer()->Start(); 6307 Object*** store_buffer_top = store_buffer()->Top(); 6308 6309 Object** limit = reinterpret_cast<Object**>(end); 6310 CheckStoreBuffer(this, 6311 current, 6312 limit, 6313 &store_buffer_position, 6314 store_buffer_top, 6315 &EverythingsAPointer, 6316 space->top(), 6317 space->limit()); 6318 } 6319 } 6320 6321 6322 void Heap::MapSpaceCheckStoreBuffer() { 6323 MapSpace* space = map_space(); 6324 PageIterator pages(space); 6325 6326 store_buffer()->SortUniq(); 6327 6328 while (pages.has_next()) { 6329 Page* page = pages.next(); 6330 Object** current = reinterpret_cast<Object**>(page->area_start()); 6331 6332 Address end = page->area_end(); 6333 6334 Object*** store_buffer_position = store_buffer()->Start(); 6335 Object*** store_buffer_top = store_buffer()->Top(); 6336 6337 Object** limit = reinterpret_cast<Object**>(end); 6338 CheckStoreBuffer(this, 6339 current, 6340 limit, 6341 &store_buffer_position, 6342 store_buffer_top, 6343 &IsAMapPointerAddress, 6344 space->top(), 6345 space->limit()); 6346 } 6347 } 6348 6349 6350 void Heap::LargeObjectSpaceCheckStoreBuffer() { 6351 LargeObjectIterator it(lo_space()); 6352 for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) { 6353 // We only have code, sequential strings, or fixed arrays in large 6354 // object space, and only fixed arrays can possibly contain pointers to 6355 // the young generation. 6356 if (object->IsFixedArray()) { 6357 Object*** store_buffer_position = store_buffer()->Start(); 6358 Object*** store_buffer_top = store_buffer()->Top(); 6359 Object** current = reinterpret_cast<Object**>(object->address()); 6360 Object** limit = 6361 reinterpret_cast<Object**>(object->address() + object->Size()); 6362 CheckStoreBuffer(this, 6363 current, 6364 limit, 6365 &store_buffer_position, 6366 store_buffer_top, 6367 &EverythingsAPointer, 6368 NULL, 6369 NULL); 6370 } 6371 } 6372 } 6373 #endif 6374 6375 6376 void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) { 6377 IterateStrongRoots(v, mode); 6378 IterateWeakRoots(v, mode); 6379 } 6380 6381 6382 void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { 6383 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kStringTableRootIndex])); 6384 v->Synchronize(VisitorSynchronization::kStringTable); 6385 if (mode != VISIT_ALL_IN_SCAVENGE && 6386 mode != VISIT_ALL_IN_SWEEP_NEWSPACE) { 6387 // Scavenge collections have special processing for this. 6388 external_string_table_.Iterate(v); 6389 } 6390 v->Synchronize(VisitorSynchronization::kExternalStringsTable); 6391 } 6392 6393 6394 void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { 6395 v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]); 6396 v->Synchronize(VisitorSynchronization::kStrongRootList); 6397 6398 v->VisitPointer(BitCast<Object**>(&hidden_string_)); 6399 v->Synchronize(VisitorSynchronization::kInternalizedString); 6400 6401 isolate_->bootstrapper()->Iterate(v); 6402 v->Synchronize(VisitorSynchronization::kBootstrapper); 6403 isolate_->Iterate(v); 6404 v->Synchronize(VisitorSynchronization::kTop); 6405 Relocatable::Iterate(isolate_, v); 6406 v->Synchronize(VisitorSynchronization::kRelocatable); 6407 6408 #ifdef ENABLE_DEBUGGER_SUPPORT 6409 isolate_->debug()->Iterate(v); 6410 if (isolate_->deoptimizer_data() != NULL) { 6411 isolate_->deoptimizer_data()->Iterate(v); 6412 } 6413 #endif 6414 v->Synchronize(VisitorSynchronization::kDebug); 6415 isolate_->compilation_cache()->Iterate(v); 6416 v->Synchronize(VisitorSynchronization::kCompilationCache); 6417 6418 // Iterate over local handles in handle scopes. 6419 isolate_->handle_scope_implementer()->Iterate(v); 6420 isolate_->IterateDeferredHandles(v); 6421 v->Synchronize(VisitorSynchronization::kHandleScope); 6422 6423 // Iterate over the builtin code objects and code stubs in the 6424 // heap. Note that it is not necessary to iterate over code objects 6425 // on scavenge collections. 6426 if (mode != VISIT_ALL_IN_SCAVENGE) { 6427 isolate_->builtins()->IterateBuiltins(v); 6428 } 6429 v->Synchronize(VisitorSynchronization::kBuiltins); 6430 6431 // Iterate over global handles. 6432 switch (mode) { 6433 case VISIT_ONLY_STRONG: 6434 isolate_->global_handles()->IterateStrongRoots(v); 6435 break; 6436 case VISIT_ALL_IN_SCAVENGE: 6437 isolate_->global_handles()->IterateNewSpaceStrongAndDependentRoots(v); 6438 break; 6439 case VISIT_ALL_IN_SWEEP_NEWSPACE: 6440 case VISIT_ALL: 6441 isolate_->global_handles()->IterateAllRoots(v); 6442 break; 6443 } 6444 v->Synchronize(VisitorSynchronization::kGlobalHandles); 6445 6446 // Iterate over eternal handles. 6447 if (mode == VISIT_ALL_IN_SCAVENGE) { 6448 isolate_->eternal_handles()->IterateNewSpaceRoots(v); 6449 } else { 6450 isolate_->eternal_handles()->IterateAllRoots(v); 6451 } 6452 v->Synchronize(VisitorSynchronization::kEternalHandles); 6453 6454 // Iterate over pointers being held by inactive threads. 6455 isolate_->thread_manager()->Iterate(v); 6456 v->Synchronize(VisitorSynchronization::kThreadManager); 6457 6458 // Iterate over the pointers the Serialization/Deserialization code is 6459 // holding. 6460 // During garbage collection this keeps the partial snapshot cache alive. 6461 // During deserialization of the startup snapshot this creates the partial 6462 // snapshot cache and deserializes the objects it refers to. During 6463 // serialization this does nothing, since the partial snapshot cache is 6464 // empty. However the next thing we do is create the partial snapshot, 6465 // filling up the partial snapshot cache with objects it needs as we go. 6466 SerializerDeserializer::Iterate(isolate_, v); 6467 // We don't do a v->Synchronize call here, because in debug mode that will 6468 // output a flag to the snapshot. However at this point the serializer and 6469 // deserializer are deliberately a little unsynchronized (see above) so the 6470 // checking of the sync flag in the snapshot would fail. 6471 } 6472 6473 6474 // TODO(1236194): Since the heap size is configurable on the command line 6475 // and through the API, we should gracefully handle the case that the heap 6476 // size is not big enough to fit all the initial objects. 6477 bool Heap::ConfigureHeap(int max_semispace_size, 6478 intptr_t max_old_gen_size, 6479 intptr_t max_executable_size) { 6480 if (HasBeenSetUp()) return false; 6481 6482 if (FLAG_stress_compaction) { 6483 // This will cause more frequent GCs when stressing. 6484 max_semispace_size_ = Page::kPageSize; 6485 } 6486 6487 if (max_semispace_size > 0) { 6488 if (max_semispace_size < Page::kPageSize) { 6489 max_semispace_size = Page::kPageSize; 6490 if (FLAG_trace_gc) { 6491 PrintPID("Max semispace size cannot be less than %dkbytes\n", 6492 Page::kPageSize >> 10); 6493 } 6494 } 6495 max_semispace_size_ = max_semispace_size; 6496 } 6497 6498 if (Snapshot::IsEnabled()) { 6499 // If we are using a snapshot we always reserve the default amount 6500 // of memory for each semispace because code in the snapshot has 6501 // write-barrier code that relies on the size and alignment of new 6502 // space. We therefore cannot use a larger max semispace size 6503 // than the default reserved semispace size. 6504 if (max_semispace_size_ > reserved_semispace_size_) { 6505 max_semispace_size_ = reserved_semispace_size_; 6506 if (FLAG_trace_gc) { 6507 PrintPID("Max semispace size cannot be more than %dkbytes\n", 6508 reserved_semispace_size_ >> 10); 6509 } 6510 } 6511 } else { 6512 // If we are not using snapshots we reserve space for the actual 6513 // max semispace size. 6514 reserved_semispace_size_ = max_semispace_size_; 6515 } 6516 6517 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size; 6518 if (max_executable_size > 0) { 6519 max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize); 6520 } 6521 6522 // The max executable size must be less than or equal to the max old 6523 // generation size. 6524 if (max_executable_size_ > max_old_generation_size_) { 6525 max_executable_size_ = max_old_generation_size_; 6526 } 6527 6528 // The new space size must be a power of two to support single-bit testing 6529 // for containment. 6530 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_); 6531 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_); 6532 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_); 6533 6534 // The external allocation limit should be below 256 MB on all architectures 6535 // to avoid unnecessary low memory notifications, as that is the threshold 6536 // for some embedders. 6537 external_allocation_limit_ = 12 * max_semispace_size_; 6538 ASSERT(external_allocation_limit_ <= 256 * MB); 6539 6540 // The old generation is paged and needs at least one page for each space. 6541 int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1; 6542 max_old_generation_size_ = Max(static_cast<intptr_t>(paged_space_count * 6543 Page::kPageSize), 6544 RoundUp(max_old_generation_size_, 6545 Page::kPageSize)); 6546 6547 // We rely on being able to allocate new arrays in paged spaces. 6548 ASSERT(MaxRegularSpaceAllocationSize() >= 6549 (JSArray::kSize + 6550 FixedArray::SizeFor(JSObject::kInitialMaxFastElementArray) + 6551 AllocationMemento::kSize)); 6552 6553 configured_ = true; 6554 return true; 6555 } 6556 6557 6558 bool Heap::ConfigureHeapDefault() { 6559 return ConfigureHeap(static_cast<intptr_t>(FLAG_max_new_space_size / 2) * KB, 6560 static_cast<intptr_t>(FLAG_max_old_space_size) * MB, 6561 static_cast<intptr_t>(FLAG_max_executable_size) * MB); 6562 } 6563 6564 6565 void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { 6566 *stats->start_marker = HeapStats::kStartMarker; 6567 *stats->end_marker = HeapStats::kEndMarker; 6568 *stats->new_space_size = new_space_.SizeAsInt(); 6569 *stats->new_space_capacity = static_cast<int>(new_space_.Capacity()); 6570 *stats->old_pointer_space_size = old_pointer_space_->SizeOfObjects(); 6571 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity(); 6572 *stats->old_data_space_size = old_data_space_->SizeOfObjects(); 6573 *stats->old_data_space_capacity = old_data_space_->Capacity(); 6574 *stats->code_space_size = code_space_->SizeOfObjects(); 6575 *stats->code_space_capacity = code_space_->Capacity(); 6576 *stats->map_space_size = map_space_->SizeOfObjects(); 6577 *stats->map_space_capacity = map_space_->Capacity(); 6578 *stats->cell_space_size = cell_space_->SizeOfObjects(); 6579 *stats->cell_space_capacity = cell_space_->Capacity(); 6580 *stats->property_cell_space_size = property_cell_space_->SizeOfObjects(); 6581 *stats->property_cell_space_capacity = property_cell_space_->Capacity(); 6582 *stats->lo_space_size = lo_space_->Size(); 6583 isolate_->global_handles()->RecordStats(stats); 6584 *stats->memory_allocator_size = isolate()->memory_allocator()->Size(); 6585 *stats->memory_allocator_capacity = 6586 isolate()->memory_allocator()->Size() + 6587 isolate()->memory_allocator()->Available(); 6588 *stats->os_error = OS::GetLastError(); 6589 isolate()->memory_allocator()->Available(); 6590 if (take_snapshot) { 6591 HeapIterator iterator(this); 6592 for (HeapObject* obj = iterator.next(); 6593 obj != NULL; 6594 obj = iterator.next()) { 6595 InstanceType type = obj->map()->instance_type(); 6596 ASSERT(0 <= type && type <= LAST_TYPE); 6597 stats->objects_per_type[type]++; 6598 stats->size_per_type[type] += obj->Size(); 6599 } 6600 } 6601 } 6602 6603 6604 intptr_t Heap::PromotedSpaceSizeOfObjects() { 6605 return old_pointer_space_->SizeOfObjects() 6606 + old_data_space_->SizeOfObjects() 6607 + code_space_->SizeOfObjects() 6608 + map_space_->SizeOfObjects() 6609 + cell_space_->SizeOfObjects() 6610 + property_cell_space_->SizeOfObjects() 6611 + lo_space_->SizeOfObjects(); 6612 } 6613 6614 6615 bool Heap::AdvanceSweepers(int step_size) { 6616 ASSERT(isolate()->num_sweeper_threads() == 0); 6617 bool sweeping_complete = old_data_space()->AdvanceSweeper(step_size); 6618 sweeping_complete &= old_pointer_space()->AdvanceSweeper(step_size); 6619 return sweeping_complete; 6620 } 6621 6622 6623 int64_t Heap::PromotedExternalMemorySize() { 6624 if (amount_of_external_allocated_memory_ 6625 <= amount_of_external_allocated_memory_at_last_global_gc_) return 0; 6626 return amount_of_external_allocated_memory_ 6627 - amount_of_external_allocated_memory_at_last_global_gc_; 6628 } 6629 6630 6631 void Heap::EnableInlineAllocation() { 6632 ASSERT(inline_allocation_disabled_); 6633 inline_allocation_disabled_ = false; 6634 6635 // Update inline allocation limit for new space. 6636 new_space()->UpdateInlineAllocationLimit(0); 6637 } 6638 6639 6640 void Heap::DisableInlineAllocation() { 6641 ASSERT(!inline_allocation_disabled_); 6642 inline_allocation_disabled_ = true; 6643 6644 // Update inline allocation limit for new space. 6645 new_space()->UpdateInlineAllocationLimit(0); 6646 6647 // Update inline allocation limit for old spaces. 6648 PagedSpaces spaces(this); 6649 for (PagedSpace* space = spaces.next(); 6650 space != NULL; 6651 space = spaces.next()) { 6652 space->EmptyAllocationInfo(); 6653 } 6654 } 6655 6656 6657 V8_DECLARE_ONCE(initialize_gc_once); 6658 6659 static void InitializeGCOnce() { 6660 InitializeScavengingVisitorsTables(); 6661 NewSpaceScavenger::Initialize(); 6662 MarkCompactCollector::Initialize(); 6663 } 6664 6665 6666 bool Heap::SetUp() { 6667 #ifdef DEBUG 6668 allocation_timeout_ = FLAG_gc_interval; 6669 #endif 6670 6671 // Initialize heap spaces and initial maps and objects. Whenever something 6672 // goes wrong, just return false. The caller should check the results and 6673 // call Heap::TearDown() to release allocated memory. 6674 // 6675 // If the heap is not yet configured (e.g. through the API), configure it. 6676 // Configuration is based on the flags new-space-size (really the semispace 6677 // size) and old-space-size if set or the initial values of semispace_size_ 6678 // and old_generation_size_ otherwise. 6679 if (!configured_) { 6680 if (!ConfigureHeapDefault()) return false; 6681 } 6682 6683 CallOnce(&initialize_gc_once, &InitializeGCOnce); 6684 6685 MarkMapPointersAsEncoded(false); 6686 6687 // Set up memory allocator. 6688 if (!isolate_->memory_allocator()->SetUp(MaxReserved(), MaxExecutableSize())) 6689 return false; 6690 6691 // Set up new space. 6692 if (!new_space_.SetUp(reserved_semispace_size_, max_semispace_size_)) { 6693 return false; 6694 } 6695 6696 // Initialize old pointer space. 6697 old_pointer_space_ = 6698 new OldSpace(this, 6699 max_old_generation_size_, 6700 OLD_POINTER_SPACE, 6701 NOT_EXECUTABLE); 6702 if (old_pointer_space_ == NULL) return false; 6703 if (!old_pointer_space_->SetUp()) return false; 6704 6705 // Initialize old data space. 6706 old_data_space_ = 6707 new OldSpace(this, 6708 max_old_generation_size_, 6709 OLD_DATA_SPACE, 6710 NOT_EXECUTABLE); 6711 if (old_data_space_ == NULL) return false; 6712 if (!old_data_space_->SetUp()) return false; 6713 6714 // Initialize the code space, set its maximum capacity to the old 6715 // generation size. It needs executable memory. 6716 // On 64-bit platform(s), we put all code objects in a 2 GB range of 6717 // virtual address space, so that they can call each other with near calls. 6718 if (code_range_size_ > 0) { 6719 if (!isolate_->code_range()->SetUp(code_range_size_)) { 6720 return false; 6721 } 6722 } 6723 6724 code_space_ = 6725 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE); 6726 if (code_space_ == NULL) return false; 6727 if (!code_space_->SetUp()) return false; 6728 6729 // Initialize map space. 6730 map_space_ = new MapSpace(this, max_old_generation_size_, MAP_SPACE); 6731 if (map_space_ == NULL) return false; 6732 if (!map_space_->SetUp()) return false; 6733 6734 // Initialize simple cell space. 6735 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE); 6736 if (cell_space_ == NULL) return false; 6737 if (!cell_space_->SetUp()) return false; 6738 6739 // Initialize global property cell space. 6740 property_cell_space_ = new PropertyCellSpace(this, max_old_generation_size_, 6741 PROPERTY_CELL_SPACE); 6742 if (property_cell_space_ == NULL) return false; 6743 if (!property_cell_space_->SetUp()) return false; 6744 6745 // The large object code space may contain code or data. We set the memory 6746 // to be non-executable here for safety, but this means we need to enable it 6747 // explicitly when allocating large code objects. 6748 lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE); 6749 if (lo_space_ == NULL) return false; 6750 if (!lo_space_->SetUp()) return false; 6751 6752 // Set up the seed that is used to randomize the string hash function. 6753 ASSERT(hash_seed() == 0); 6754 if (FLAG_randomize_hashes) { 6755 if (FLAG_hash_seed == 0) { 6756 int rnd = isolate()->random_number_generator()->NextInt(); 6757 set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask)); 6758 } else { 6759 set_hash_seed(Smi::FromInt(FLAG_hash_seed)); 6760 } 6761 } 6762 6763 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity())); 6764 LOG(isolate_, IntPtrTEvent("heap-available", Available())); 6765 6766 store_buffer()->SetUp(); 6767 6768 if (FLAG_concurrent_recompilation) relocation_mutex_ = new Mutex; 6769 6770 return true; 6771 } 6772 6773 6774 bool Heap::CreateHeapObjects() { 6775 // Create initial maps. 6776 if (!CreateInitialMaps()) return false; 6777 if (!CreateApiObjects()) return false; 6778 6779 // Create initial objects 6780 if (!CreateInitialObjects()) return false; 6781 6782 native_contexts_list_ = undefined_value(); 6783 array_buffers_list_ = undefined_value(); 6784 allocation_sites_list_ = undefined_value(); 6785 weak_object_to_code_table_ = undefined_value(); 6786 return true; 6787 } 6788 6789 6790 void Heap::SetStackLimits() { 6791 ASSERT(isolate_ != NULL); 6792 ASSERT(isolate_ == isolate()); 6793 // On 64 bit machines, pointers are generally out of range of Smis. We write 6794 // something that looks like an out of range Smi to the GC. 6795 6796 // Set up the special root array entries containing the stack limits. 6797 // These are actually addresses, but the tag makes the GC ignore it. 6798 roots_[kStackLimitRootIndex] = 6799 reinterpret_cast<Object*>( 6800 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag); 6801 roots_[kRealStackLimitRootIndex] = 6802 reinterpret_cast<Object*>( 6803 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag); 6804 } 6805 6806 6807 void Heap::TearDown() { 6808 #ifdef VERIFY_HEAP 6809 if (FLAG_verify_heap) { 6810 Verify(); 6811 } 6812 #endif 6813 6814 UpdateMaximumCommitted(); 6815 6816 if (FLAG_print_cumulative_gc_stat) { 6817 PrintF("\n"); 6818 PrintF("gc_count=%d ", gc_count_); 6819 PrintF("mark_sweep_count=%d ", ms_count_); 6820 PrintF("max_gc_pause=%.1f ", get_max_gc_pause()); 6821 PrintF("total_gc_time=%.1f ", total_gc_time_ms_); 6822 PrintF("min_in_mutator=%.1f ", get_min_in_mutator()); 6823 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ", 6824 get_max_alive_after_gc()); 6825 PrintF("total_marking_time=%.1f ", marking_time()); 6826 PrintF("total_sweeping_time=%.1f ", sweeping_time()); 6827 PrintF("\n\n"); 6828 } 6829 6830 if (FLAG_print_max_heap_committed) { 6831 PrintF("\n"); 6832 PrintF("maximum_committed_by_heap=%" V8_PTR_PREFIX "d ", 6833 MaximumCommittedMemory()); 6834 PrintF("maximum_committed_by_new_space=%" V8_PTR_PREFIX "d ", 6835 new_space_.MaximumCommittedMemory()); 6836 PrintF("maximum_committed_by_old_pointer_space=%" V8_PTR_PREFIX "d ", 6837 old_data_space_->MaximumCommittedMemory()); 6838 PrintF("maximum_committed_by_old_data_space=%" V8_PTR_PREFIX "d ", 6839 old_pointer_space_->MaximumCommittedMemory()); 6840 PrintF("maximum_committed_by_old_data_space=%" V8_PTR_PREFIX "d ", 6841 old_pointer_space_->MaximumCommittedMemory()); 6842 PrintF("maximum_committed_by_code_space=%" V8_PTR_PREFIX "d ", 6843 code_space_->MaximumCommittedMemory()); 6844 PrintF("maximum_committed_by_map_space=%" V8_PTR_PREFIX "d ", 6845 map_space_->MaximumCommittedMemory()); 6846 PrintF("maximum_committed_by_cell_space=%" V8_PTR_PREFIX "d ", 6847 cell_space_->MaximumCommittedMemory()); 6848 PrintF("maximum_committed_by_property_space=%" V8_PTR_PREFIX "d ", 6849 property_cell_space_->MaximumCommittedMemory()); 6850 PrintF("maximum_committed_by_lo_space=%" V8_PTR_PREFIX "d ", 6851 lo_space_->MaximumCommittedMemory()); 6852 PrintF("\n\n"); 6853 } 6854 6855 TearDownArrayBuffers(); 6856 6857 isolate_->global_handles()->TearDown(); 6858 6859 external_string_table_.TearDown(); 6860 6861 mark_compact_collector()->TearDown(); 6862 6863 new_space_.TearDown(); 6864 6865 if (old_pointer_space_ != NULL) { 6866 old_pointer_space_->TearDown(); 6867 delete old_pointer_space_; 6868 old_pointer_space_ = NULL; 6869 } 6870 6871 if (old_data_space_ != NULL) { 6872 old_data_space_->TearDown(); 6873 delete old_data_space_; 6874 old_data_space_ = NULL; 6875 } 6876 6877 if (code_space_ != NULL) { 6878 code_space_->TearDown(); 6879 delete code_space_; 6880 code_space_ = NULL; 6881 } 6882 6883 if (map_space_ != NULL) { 6884 map_space_->TearDown(); 6885 delete map_space_; 6886 map_space_ = NULL; 6887 } 6888 6889 if (cell_space_ != NULL) { 6890 cell_space_->TearDown(); 6891 delete cell_space_; 6892 cell_space_ = NULL; 6893 } 6894 6895 if (property_cell_space_ != NULL) { 6896 property_cell_space_->TearDown(); 6897 delete property_cell_space_; 6898 property_cell_space_ = NULL; 6899 } 6900 6901 if (lo_space_ != NULL) { 6902 lo_space_->TearDown(); 6903 delete lo_space_; 6904 lo_space_ = NULL; 6905 } 6906 6907 store_buffer()->TearDown(); 6908 incremental_marking()->TearDown(); 6909 6910 isolate_->memory_allocator()->TearDown(); 6911 6912 delete relocation_mutex_; 6913 relocation_mutex_ = NULL; 6914 } 6915 6916 6917 void Heap::AddGCPrologueCallback(v8::Isolate::GCPrologueCallback callback, 6918 GCType gc_type, 6919 bool pass_isolate) { 6920 ASSERT(callback != NULL); 6921 GCPrologueCallbackPair pair(callback, gc_type, pass_isolate); 6922 ASSERT(!gc_prologue_callbacks_.Contains(pair)); 6923 return gc_prologue_callbacks_.Add(pair); 6924 } 6925 6926 6927 void Heap::RemoveGCPrologueCallback(v8::Isolate::GCPrologueCallback callback) { 6928 ASSERT(callback != NULL); 6929 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { 6930 if (gc_prologue_callbacks_[i].callback == callback) { 6931 gc_prologue_callbacks_.Remove(i); 6932 return; 6933 } 6934 } 6935 UNREACHABLE(); 6936 } 6937 6938 6939 void Heap::AddGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback, 6940 GCType gc_type, 6941 bool pass_isolate) { 6942 ASSERT(callback != NULL); 6943 GCEpilogueCallbackPair pair(callback, gc_type, pass_isolate); 6944 ASSERT(!gc_epilogue_callbacks_.Contains(pair)); 6945 return gc_epilogue_callbacks_.Add(pair); 6946 } 6947 6948 6949 void Heap::RemoveGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback) { 6950 ASSERT(callback != NULL); 6951 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) { 6952 if (gc_epilogue_callbacks_[i].callback == callback) { 6953 gc_epilogue_callbacks_.Remove(i); 6954 return; 6955 } 6956 } 6957 UNREACHABLE(); 6958 } 6959 6960 6961 MaybeObject* Heap::AddWeakObjectToCodeDependency(Object* obj, 6962 DependentCode* dep) { 6963 ASSERT(!InNewSpace(obj)); 6964 ASSERT(!InNewSpace(dep)); 6965 MaybeObject* maybe_obj = 6966 WeakHashTable::cast(weak_object_to_code_table_)->Put(obj, dep); 6967 WeakHashTable* table; 6968 if (!maybe_obj->To(&table)) return maybe_obj; 6969 if (ShouldZapGarbage() && weak_object_to_code_table_ != table) { 6970 WeakHashTable::cast(weak_object_to_code_table_)->Zap(the_hole_value()); 6971 } 6972 set_weak_object_to_code_table(table); 6973 ASSERT_EQ(dep, WeakHashTable::cast(weak_object_to_code_table_)->Lookup(obj)); 6974 return weak_object_to_code_table_; 6975 } 6976 6977 6978 DependentCode* Heap::LookupWeakObjectToCodeDependency(Object* obj) { 6979 Object* dep = WeakHashTable::cast(weak_object_to_code_table_)->Lookup(obj); 6980 if (dep->IsDependentCode()) return DependentCode::cast(dep); 6981 return DependentCode::cast(empty_fixed_array()); 6982 } 6983 6984 6985 void Heap::EnsureWeakObjectToCodeTable() { 6986 if (!weak_object_to_code_table()->IsHashTable()) { 6987 set_weak_object_to_code_table(*isolate()->factory()->NewWeakHashTable(16)); 6988 } 6989 } 6990 6991 6992 #ifdef DEBUG 6993 6994 class PrintHandleVisitor: public ObjectVisitor { 6995 public: 6996 void VisitPointers(Object** start, Object** end) { 6997 for (Object** p = start; p < end; p++) 6998 PrintF(" handle %p to %p\n", 6999 reinterpret_cast<void*>(p), 7000 reinterpret_cast<void*>(*p)); 7001 } 7002 }; 7003 7004 7005 void Heap::PrintHandles() { 7006 PrintF("Handles:\n"); 7007 PrintHandleVisitor v; 7008 isolate_->handle_scope_implementer()->Iterate(&v); 7009 } 7010 7011 #endif 7012 7013 7014 Space* AllSpaces::next() { 7015 switch (counter_++) { 7016 case NEW_SPACE: 7017 return heap_->new_space(); 7018 case OLD_POINTER_SPACE: 7019 return heap_->old_pointer_space(); 7020 case OLD_DATA_SPACE: 7021 return heap_->old_data_space(); 7022 case CODE_SPACE: 7023 return heap_->code_space(); 7024 case MAP_SPACE: 7025 return heap_->map_space(); 7026 case CELL_SPACE: 7027 return heap_->cell_space(); 7028 case PROPERTY_CELL_SPACE: 7029 return heap_->property_cell_space(); 7030 case LO_SPACE: 7031 return heap_->lo_space(); 7032 default: 7033 return NULL; 7034 } 7035 } 7036 7037 7038 PagedSpace* PagedSpaces::next() { 7039 switch (counter_++) { 7040 case OLD_POINTER_SPACE: 7041 return heap_->old_pointer_space(); 7042 case OLD_DATA_SPACE: 7043 return heap_->old_data_space(); 7044 case CODE_SPACE: 7045 return heap_->code_space(); 7046 case MAP_SPACE: 7047 return heap_->map_space(); 7048 case CELL_SPACE: 7049 return heap_->cell_space(); 7050 case PROPERTY_CELL_SPACE: 7051 return heap_->property_cell_space(); 7052 default: 7053 return NULL; 7054 } 7055 } 7056 7057 7058 7059 OldSpace* OldSpaces::next() { 7060 switch (counter_++) { 7061 case OLD_POINTER_SPACE: 7062 return heap_->old_pointer_space(); 7063 case OLD_DATA_SPACE: 7064 return heap_->old_data_space(); 7065 case CODE_SPACE: 7066 return heap_->code_space(); 7067 default: 7068 return NULL; 7069 } 7070 } 7071 7072 7073 SpaceIterator::SpaceIterator(Heap* heap) 7074 : heap_(heap), 7075 current_space_(FIRST_SPACE), 7076 iterator_(NULL), 7077 size_func_(NULL) { 7078 } 7079 7080 7081 SpaceIterator::SpaceIterator(Heap* heap, HeapObjectCallback size_func) 7082 : heap_(heap), 7083 current_space_(FIRST_SPACE), 7084 iterator_(NULL), 7085 size_func_(size_func) { 7086 } 7087 7088 7089 SpaceIterator::~SpaceIterator() { 7090 // Delete active iterator if any. 7091 delete iterator_; 7092 } 7093 7094 7095 bool SpaceIterator::has_next() { 7096 // Iterate until no more spaces. 7097 return current_space_ != LAST_SPACE; 7098 } 7099 7100 7101 ObjectIterator* SpaceIterator::next() { 7102 if (iterator_ != NULL) { 7103 delete iterator_; 7104 iterator_ = NULL; 7105 // Move to the next space 7106 current_space_++; 7107 if (current_space_ > LAST_SPACE) { 7108 return NULL; 7109 } 7110 } 7111 7112 // Return iterator for the new current space. 7113 return CreateIterator(); 7114 } 7115 7116 7117 // Create an iterator for the space to iterate. 7118 ObjectIterator* SpaceIterator::CreateIterator() { 7119 ASSERT(iterator_ == NULL); 7120 7121 switch (current_space_) { 7122 case NEW_SPACE: 7123 iterator_ = new SemiSpaceIterator(heap_->new_space(), size_func_); 7124 break; 7125 case OLD_POINTER_SPACE: 7126 iterator_ = 7127 new HeapObjectIterator(heap_->old_pointer_space(), size_func_); 7128 break; 7129 case OLD_DATA_SPACE: 7130 iterator_ = new HeapObjectIterator(heap_->old_data_space(), size_func_); 7131 break; 7132 case CODE_SPACE: 7133 iterator_ = new HeapObjectIterator(heap_->code_space(), size_func_); 7134 break; 7135 case MAP_SPACE: 7136 iterator_ = new HeapObjectIterator(heap_->map_space(), size_func_); 7137 break; 7138 case CELL_SPACE: 7139 iterator_ = new HeapObjectIterator(heap_->cell_space(), size_func_); 7140 break; 7141 case PROPERTY_CELL_SPACE: 7142 iterator_ = new HeapObjectIterator(heap_->property_cell_space(), 7143 size_func_); 7144 break; 7145 case LO_SPACE: 7146 iterator_ = new LargeObjectIterator(heap_->lo_space(), size_func_); 7147 break; 7148 } 7149 7150 // Return the newly allocated iterator; 7151 ASSERT(iterator_ != NULL); 7152 return iterator_; 7153 } 7154 7155 7156 class HeapObjectsFilter { 7157 public: 7158 virtual ~HeapObjectsFilter() {} 7159 virtual bool SkipObject(HeapObject* object) = 0; 7160 }; 7161 7162 7163 class UnreachableObjectsFilter : public HeapObjectsFilter { 7164 public: 7165 explicit UnreachableObjectsFilter(Heap* heap) : heap_(heap) { 7166 MarkReachableObjects(); 7167 } 7168 7169 ~UnreachableObjectsFilter() { 7170 heap_->mark_compact_collector()->ClearMarkbits(); 7171 } 7172 7173 bool SkipObject(HeapObject* object) { 7174 MarkBit mark_bit = Marking::MarkBitFrom(object); 7175 return !mark_bit.Get(); 7176 } 7177 7178 private: 7179 class MarkingVisitor : public ObjectVisitor { 7180 public: 7181 MarkingVisitor() : marking_stack_(10) {} 7182 7183 void VisitPointers(Object** start, Object** end) { 7184 for (Object** p = start; p < end; p++) { 7185 if (!(*p)->IsHeapObject()) continue; 7186 HeapObject* obj = HeapObject::cast(*p); 7187 MarkBit mark_bit = Marking::MarkBitFrom(obj); 7188 if (!mark_bit.Get()) { 7189 mark_bit.Set(); 7190 marking_stack_.Add(obj); 7191 } 7192 } 7193 } 7194 7195 void TransitiveClosure() { 7196 while (!marking_stack_.is_empty()) { 7197 HeapObject* obj = marking_stack_.RemoveLast(); 7198 obj->Iterate(this); 7199 } 7200 } 7201 7202 private: 7203 List<HeapObject*> marking_stack_; 7204 }; 7205 7206 void MarkReachableObjects() { 7207 MarkingVisitor visitor; 7208 heap_->IterateRoots(&visitor, VISIT_ALL); 7209 visitor.TransitiveClosure(); 7210 } 7211 7212 Heap* heap_; 7213 DisallowHeapAllocation no_allocation_; 7214 }; 7215 7216 7217 HeapIterator::HeapIterator(Heap* heap) 7218 : heap_(heap), 7219 filtering_(HeapIterator::kNoFiltering), 7220 filter_(NULL) { 7221 Init(); 7222 } 7223 7224 7225 HeapIterator::HeapIterator(Heap* heap, 7226 HeapIterator::HeapObjectsFiltering filtering) 7227 : heap_(heap), 7228 filtering_(filtering), 7229 filter_(NULL) { 7230 Init(); 7231 } 7232 7233 7234 HeapIterator::~HeapIterator() { 7235 Shutdown(); 7236 } 7237 7238 7239 void HeapIterator::Init() { 7240 // Start the iteration. 7241 space_iterator_ = new SpaceIterator(heap_); 7242 switch (filtering_) { 7243 case kFilterUnreachable: 7244 filter_ = new UnreachableObjectsFilter(heap_); 7245 break; 7246 default: 7247 break; 7248 } 7249 object_iterator_ = space_iterator_->next(); 7250 } 7251 7252 7253 void HeapIterator::Shutdown() { 7254 #ifdef DEBUG 7255 // Assert that in filtering mode we have iterated through all 7256 // objects. Otherwise, heap will be left in an inconsistent state. 7257 if (filtering_ != kNoFiltering) { 7258 ASSERT(object_iterator_ == NULL); 7259 } 7260 #endif 7261 // Make sure the last iterator is deallocated. 7262 delete space_iterator_; 7263 space_iterator_ = NULL; 7264 object_iterator_ = NULL; 7265 delete filter_; 7266 filter_ = NULL; 7267 } 7268 7269 7270 HeapObject* HeapIterator::next() { 7271 if (filter_ == NULL) return NextObject(); 7272 7273 HeapObject* obj = NextObject(); 7274 while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject(); 7275 return obj; 7276 } 7277 7278 7279 HeapObject* HeapIterator::NextObject() { 7280 // No iterator means we are done. 7281 if (object_iterator_ == NULL) return NULL; 7282 7283 if (HeapObject* obj = object_iterator_->next_object()) { 7284 // If the current iterator has more objects we are fine. 7285 return obj; 7286 } else { 7287 // Go though the spaces looking for one that has objects. 7288 while (space_iterator_->has_next()) { 7289 object_iterator_ = space_iterator_->next(); 7290 if (HeapObject* obj = object_iterator_->next_object()) { 7291 return obj; 7292 } 7293 } 7294 } 7295 // Done with the last space. 7296 object_iterator_ = NULL; 7297 return NULL; 7298 } 7299 7300 7301 void HeapIterator::reset() { 7302 // Restart the iterator. 7303 Shutdown(); 7304 Init(); 7305 } 7306 7307 7308 #ifdef DEBUG 7309 7310 Object* const PathTracer::kAnyGlobalObject = NULL; 7311 7312 class PathTracer::MarkVisitor: public ObjectVisitor { 7313 public: 7314 explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {} 7315 void VisitPointers(Object** start, Object** end) { 7316 // Scan all HeapObject pointers in [start, end) 7317 for (Object** p = start; !tracer_->found() && (p < end); p++) { 7318 if ((*p)->IsHeapObject()) 7319 tracer_->MarkRecursively(p, this); 7320 } 7321 } 7322 7323 private: 7324 PathTracer* tracer_; 7325 }; 7326 7327 7328 class PathTracer::UnmarkVisitor: public ObjectVisitor { 7329 public: 7330 explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {} 7331 void VisitPointers(Object** start, Object** end) { 7332 // Scan all HeapObject pointers in [start, end) 7333 for (Object** p = start; p < end; p++) { 7334 if ((*p)->IsHeapObject()) 7335 tracer_->UnmarkRecursively(p, this); 7336 } 7337 } 7338 7339 private: 7340 PathTracer* tracer_; 7341 }; 7342 7343 7344 void PathTracer::VisitPointers(Object** start, Object** end) { 7345 bool done = ((what_to_find_ == FIND_FIRST) && found_target_); 7346 // Visit all HeapObject pointers in [start, end) 7347 for (Object** p = start; !done && (p < end); p++) { 7348 if ((*p)->IsHeapObject()) { 7349 TracePathFrom(p); 7350 done = ((what_to_find_ == FIND_FIRST) && found_target_); 7351 } 7352 } 7353 } 7354 7355 7356 void PathTracer::Reset() { 7357 found_target_ = false; 7358 object_stack_.Clear(); 7359 } 7360 7361 7362 void PathTracer::TracePathFrom(Object** root) { 7363 ASSERT((search_target_ == kAnyGlobalObject) || 7364 search_target_->IsHeapObject()); 7365 found_target_in_trace_ = false; 7366 Reset(); 7367 7368 MarkVisitor mark_visitor(this); 7369 MarkRecursively(root, &mark_visitor); 7370 7371 UnmarkVisitor unmark_visitor(this); 7372 UnmarkRecursively(root, &unmark_visitor); 7373 7374 ProcessResults(); 7375 } 7376 7377 7378 static bool SafeIsNativeContext(HeapObject* obj) { 7379 return obj->map() == obj->GetHeap()->raw_unchecked_native_context_map(); 7380 } 7381 7382 7383 void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) { 7384 if (!(*p)->IsHeapObject()) return; 7385 7386 HeapObject* obj = HeapObject::cast(*p); 7387 7388 Object* map = obj->map(); 7389 7390 if (!map->IsHeapObject()) return; // visited before 7391 7392 if (found_target_in_trace_) return; // stop if target found 7393 object_stack_.Add(obj); 7394 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) || 7395 (obj == search_target_)) { 7396 found_target_in_trace_ = true; 7397 found_target_ = true; 7398 return; 7399 } 7400 7401 bool is_native_context = SafeIsNativeContext(obj); 7402 7403 // not visited yet 7404 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map)); 7405 7406 Address map_addr = map_p->address(); 7407 7408 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag)); 7409 7410 // Scan the object body. 7411 if (is_native_context && (visit_mode_ == VISIT_ONLY_STRONG)) { 7412 // This is specialized to scan Context's properly. 7413 Object** start = reinterpret_cast<Object**>(obj->address() + 7414 Context::kHeaderSize); 7415 Object** end = reinterpret_cast<Object**>(obj->address() + 7416 Context::kHeaderSize + Context::FIRST_WEAK_SLOT * kPointerSize); 7417 mark_visitor->VisitPointers(start, end); 7418 } else { 7419 obj->IterateBody(map_p->instance_type(), 7420 obj->SizeFromMap(map_p), 7421 mark_visitor); 7422 } 7423 7424 // Scan the map after the body because the body is a lot more interesting 7425 // when doing leak detection. 7426 MarkRecursively(&map, mark_visitor); 7427 7428 if (!found_target_in_trace_) // don't pop if found the target 7429 object_stack_.RemoveLast(); 7430 } 7431 7432 7433 void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) { 7434 if (!(*p)->IsHeapObject()) return; 7435 7436 HeapObject* obj = HeapObject::cast(*p); 7437 7438 Object* map = obj->map(); 7439 7440 if (map->IsHeapObject()) return; // unmarked already 7441 7442 Address map_addr = reinterpret_cast<Address>(map); 7443 7444 map_addr -= kMarkTag; 7445 7446 ASSERT_TAG_ALIGNED(map_addr); 7447 7448 HeapObject* map_p = HeapObject::FromAddress(map_addr); 7449 7450 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p)); 7451 7452 UnmarkRecursively(reinterpret_cast<Object**>(&map_p), unmark_visitor); 7453 7454 obj->IterateBody(Map::cast(map_p)->instance_type(), 7455 obj->SizeFromMap(Map::cast(map_p)), 7456 unmark_visitor); 7457 } 7458 7459 7460 void PathTracer::ProcessResults() { 7461 if (found_target_) { 7462 PrintF("=====================================\n"); 7463 PrintF("==== Path to object ====\n"); 7464 PrintF("=====================================\n\n"); 7465 7466 ASSERT(!object_stack_.is_empty()); 7467 for (int i = 0; i < object_stack_.length(); i++) { 7468 if (i > 0) PrintF("\n |\n |\n V\n\n"); 7469 Object* obj = object_stack_[i]; 7470 obj->Print(); 7471 } 7472 PrintF("=====================================\n"); 7473 } 7474 } 7475 7476 7477 // Triggers a depth-first traversal of reachable objects from one 7478 // given root object and finds a path to a specific heap object and 7479 // prints it. 7480 void Heap::TracePathToObjectFrom(Object* target, Object* root) { 7481 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL); 7482 tracer.VisitPointer(&root); 7483 } 7484 7485 7486 // Triggers a depth-first traversal of reachable objects from roots 7487 // and finds a path to a specific heap object and prints it. 7488 void Heap::TracePathToObject(Object* target) { 7489 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL); 7490 IterateRoots(&tracer, VISIT_ONLY_STRONG); 7491 } 7492 7493 7494 // Triggers a depth-first traversal of reachable objects from roots 7495 // and finds a path to any global object and prints it. Useful for 7496 // determining the source for leaks of global objects. 7497 void Heap::TracePathToGlobal() { 7498 PathTracer tracer(PathTracer::kAnyGlobalObject, 7499 PathTracer::FIND_ALL, 7500 VISIT_ALL); 7501 IterateRoots(&tracer, VISIT_ONLY_STRONG); 7502 } 7503 #endif 7504 7505 7506 static intptr_t CountTotalHolesSize(Heap* heap) { 7507 intptr_t holes_size = 0; 7508 OldSpaces spaces(heap); 7509 for (OldSpace* space = spaces.next(); 7510 space != NULL; 7511 space = spaces.next()) { 7512 holes_size += space->Waste() + space->Available(); 7513 } 7514 return holes_size; 7515 } 7516 7517 7518 GCTracer::GCTracer(Heap* heap, 7519 const char* gc_reason, 7520 const char* collector_reason) 7521 : start_time_(0.0), 7522 start_object_size_(0), 7523 start_memory_size_(0), 7524 gc_count_(0), 7525 full_gc_count_(0), 7526 allocated_since_last_gc_(0), 7527 spent_in_mutator_(0), 7528 promoted_objects_size_(0), 7529 nodes_died_in_new_space_(0), 7530 nodes_copied_in_new_space_(0), 7531 nodes_promoted_(0), 7532 heap_(heap), 7533 gc_reason_(gc_reason), 7534 collector_reason_(collector_reason) { 7535 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; 7536 start_time_ = OS::TimeCurrentMillis(); 7537 start_object_size_ = heap_->SizeOfObjects(); 7538 start_memory_size_ = heap_->isolate()->memory_allocator()->Size(); 7539 7540 for (int i = 0; i < Scope::kNumberOfScopes; i++) { 7541 scopes_[i] = 0; 7542 } 7543 7544 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize(heap); 7545 7546 allocated_since_last_gc_ = 7547 heap_->SizeOfObjects() - heap_->alive_after_last_gc_; 7548 7549 if (heap_->last_gc_end_timestamp_ > 0) { 7550 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0); 7551 } 7552 7553 steps_count_ = heap_->incremental_marking()->steps_count(); 7554 steps_took_ = heap_->incremental_marking()->steps_took(); 7555 longest_step_ = heap_->incremental_marking()->longest_step(); 7556 steps_count_since_last_gc_ = 7557 heap_->incremental_marking()->steps_count_since_last_gc(); 7558 steps_took_since_last_gc_ = 7559 heap_->incremental_marking()->steps_took_since_last_gc(); 7560 } 7561 7562 7563 GCTracer::~GCTracer() { 7564 // Printf ONE line iff flag is set. 7565 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; 7566 7567 bool first_gc = (heap_->last_gc_end_timestamp_ == 0); 7568 7569 heap_->alive_after_last_gc_ = heap_->SizeOfObjects(); 7570 heap_->last_gc_end_timestamp_ = OS::TimeCurrentMillis(); 7571 7572 double time = heap_->last_gc_end_timestamp_ - start_time_; 7573 7574 // Update cumulative GC statistics if required. 7575 if (FLAG_print_cumulative_gc_stat) { 7576 heap_->total_gc_time_ms_ += time; 7577 heap_->max_gc_pause_ = Max(heap_->max_gc_pause_, time); 7578 heap_->max_alive_after_gc_ = Max(heap_->max_alive_after_gc_, 7579 heap_->alive_after_last_gc_); 7580 if (!first_gc) { 7581 heap_->min_in_mutator_ = Min(heap_->min_in_mutator_, 7582 spent_in_mutator_); 7583 } 7584 } else if (FLAG_trace_gc_verbose) { 7585 heap_->total_gc_time_ms_ += time; 7586 } 7587 7588 if (collector_ == SCAVENGER && FLAG_trace_gc_ignore_scavenger) return; 7589 7590 heap_->AddMarkingTime(scopes_[Scope::MC_MARK]); 7591 7592 if (FLAG_print_cumulative_gc_stat && !FLAG_trace_gc) return; 7593 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init()); 7594 7595 if (!FLAG_trace_gc_nvp) { 7596 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]); 7597 7598 double end_memory_size_mb = 7599 static_cast<double>(heap_->isolate()->memory_allocator()->Size()) / MB; 7600 7601 PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ", 7602 CollectorString(), 7603 static_cast<double>(start_object_size_) / MB, 7604 static_cast<double>(start_memory_size_) / MB, 7605 SizeOfHeapObjects(), 7606 end_memory_size_mb); 7607 7608 if (external_time > 0) PrintF("%d / ", external_time); 7609 PrintF("%.1f ms", time); 7610 if (steps_count_ > 0) { 7611 if (collector_ == SCAVENGER) { 7612 PrintF(" (+ %.1f ms in %d steps since last GC)", 7613 steps_took_since_last_gc_, 7614 steps_count_since_last_gc_); 7615 } else { 7616 PrintF(" (+ %.1f ms in %d steps since start of marking, " 7617 "biggest step %.1f ms)", 7618 steps_took_, 7619 steps_count_, 7620 longest_step_); 7621 } 7622 } 7623 7624 if (gc_reason_ != NULL) { 7625 PrintF(" [%s]", gc_reason_); 7626 } 7627 7628 if (collector_reason_ != NULL) { 7629 PrintF(" [%s]", collector_reason_); 7630 } 7631 7632 PrintF(".\n"); 7633 } else { 7634 PrintF("pause=%.1f ", time); 7635 PrintF("mutator=%.1f ", spent_in_mutator_); 7636 PrintF("gc="); 7637 switch (collector_) { 7638 case SCAVENGER: 7639 PrintF("s"); 7640 break; 7641 case MARK_COMPACTOR: 7642 PrintF("ms"); 7643 break; 7644 default: 7645 UNREACHABLE(); 7646 } 7647 PrintF(" "); 7648 7649 PrintF("external=%.1f ", scopes_[Scope::EXTERNAL]); 7650 PrintF("mark=%.1f ", scopes_[Scope::MC_MARK]); 7651 PrintF("sweep=%.1f ", scopes_[Scope::MC_SWEEP]); 7652 PrintF("sweepns=%.1f ", scopes_[Scope::MC_SWEEP_NEWSPACE]); 7653 PrintF("evacuate=%.1f ", scopes_[Scope::MC_EVACUATE_PAGES]); 7654 PrintF("new_new=%.1f ", scopes_[Scope::MC_UPDATE_NEW_TO_NEW_POINTERS]); 7655 PrintF("root_new=%.1f ", scopes_[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS]); 7656 PrintF("old_new=%.1f ", scopes_[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS]); 7657 PrintF("compaction_ptrs=%.1f ", 7658 scopes_[Scope::MC_UPDATE_POINTERS_TO_EVACUATED]); 7659 PrintF("intracompaction_ptrs=%.1f ", 7660 scopes_[Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]); 7661 PrintF("misc_compaction=%.1f ", scopes_[Scope::MC_UPDATE_MISC_POINTERS]); 7662 PrintF("weakcollection_process=%.1f ", 7663 scopes_[Scope::MC_WEAKCOLLECTION_PROCESS]); 7664 PrintF("weakcollection_clear=%.1f ", 7665 scopes_[Scope::MC_WEAKCOLLECTION_CLEAR]); 7666 7667 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_); 7668 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects()); 7669 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", 7670 in_free_list_or_wasted_before_gc_); 7671 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize(heap_)); 7672 7673 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_); 7674 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_); 7675 PrintF("nodes_died_in_new=%d ", nodes_died_in_new_space_); 7676 PrintF("nodes_copied_in_new=%d ", nodes_copied_in_new_space_); 7677 PrintF("nodes_promoted=%d ", nodes_promoted_); 7678 7679 if (collector_ == SCAVENGER) { 7680 PrintF("stepscount=%d ", steps_count_since_last_gc_); 7681 PrintF("stepstook=%.1f ", steps_took_since_last_gc_); 7682 } else { 7683 PrintF("stepscount=%d ", steps_count_); 7684 PrintF("stepstook=%.1f ", steps_took_); 7685 PrintF("longeststep=%.1f ", longest_step_); 7686 } 7687 7688 PrintF("\n"); 7689 } 7690 7691 heap_->PrintShortHeapStatistics(); 7692 } 7693 7694 7695 const char* GCTracer::CollectorString() { 7696 switch (collector_) { 7697 case SCAVENGER: 7698 return "Scavenge"; 7699 case MARK_COMPACTOR: 7700 return "Mark-sweep"; 7701 } 7702 return "Unknown GC"; 7703 } 7704 7705 7706 int KeyedLookupCache::Hash(Map* map, Name* name) { 7707 // Uses only lower 32 bits if pointers are larger. 7708 uintptr_t addr_hash = 7709 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift; 7710 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask); 7711 } 7712 7713 7714 int KeyedLookupCache::Lookup(Map* map, Name* name) { 7715 int index = (Hash(map, name) & kHashMask); 7716 for (int i = 0; i < kEntriesPerBucket; i++) { 7717 Key& key = keys_[index + i]; 7718 if ((key.map == map) && key.name->Equals(name)) { 7719 return field_offsets_[index + i]; 7720 } 7721 } 7722 return kNotFound; 7723 } 7724 7725 7726 void KeyedLookupCache::Update(Map* map, Name* name, int field_offset) { 7727 if (!name->IsUniqueName()) { 7728 String* internalized_string; 7729 if (!map->GetIsolate()->heap()->InternalizeStringIfExists( 7730 String::cast(name), &internalized_string)) { 7731 return; 7732 } 7733 name = internalized_string; 7734 } 7735 // This cache is cleared only between mark compact passes, so we expect the 7736 // cache to only contain old space names. 7737 ASSERT(!map->GetIsolate()->heap()->InNewSpace(name)); 7738 7739 int index = (Hash(map, name) & kHashMask); 7740 // After a GC there will be free slots, so we use them in order (this may 7741 // help to get the most frequently used one in position 0). 7742 for (int i = 0; i< kEntriesPerBucket; i++) { 7743 Key& key = keys_[index]; 7744 Object* free_entry_indicator = NULL; 7745 if (key.map == free_entry_indicator) { 7746 key.map = map; 7747 key.name = name; 7748 field_offsets_[index + i] = field_offset; 7749 return; 7750 } 7751 } 7752 // No free entry found in this bucket, so we move them all down one and 7753 // put the new entry at position zero. 7754 for (int i = kEntriesPerBucket - 1; i > 0; i--) { 7755 Key& key = keys_[index + i]; 7756 Key& key2 = keys_[index + i - 1]; 7757 key = key2; 7758 field_offsets_[index + i] = field_offsets_[index + i - 1]; 7759 } 7760 7761 // Write the new first entry. 7762 Key& key = keys_[index]; 7763 key.map = map; 7764 key.name = name; 7765 field_offsets_[index] = field_offset; 7766 } 7767 7768 7769 void KeyedLookupCache::Clear() { 7770 for (int index = 0; index < kLength; index++) keys_[index].map = NULL; 7771 } 7772 7773 7774 void DescriptorLookupCache::Clear() { 7775 for (int index = 0; index < kLength; index++) keys_[index].source = NULL; 7776 } 7777 7778 7779 #ifdef DEBUG 7780 void Heap::GarbageCollectionGreedyCheck() { 7781 ASSERT(FLAG_gc_greedy); 7782 if (isolate_->bootstrapper()->IsActive()) return; 7783 if (disallow_allocation_failure()) return; 7784 CollectGarbage(NEW_SPACE); 7785 } 7786 #endif 7787 7788 7789 TranscendentalCache::SubCache::SubCache(Isolate* isolate, Type t) 7790 : type_(t), 7791 isolate_(isolate) { 7792 uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't 7793 uint32_t in1 = 0xffffffffu; // generated by the FPU. 7794 for (int i = 0; i < kCacheSize; i++) { 7795 elements_[i].in[0] = in0; 7796 elements_[i].in[1] = in1; 7797 elements_[i].output = NULL; 7798 } 7799 } 7800 7801 7802 void TranscendentalCache::Clear() { 7803 for (int i = 0; i < kNumberOfCaches; i++) { 7804 if (caches_[i] != NULL) { 7805 delete caches_[i]; 7806 caches_[i] = NULL; 7807 } 7808 } 7809 } 7810 7811 7812 void ExternalStringTable::CleanUp() { 7813 int last = 0; 7814 for (int i = 0; i < new_space_strings_.length(); ++i) { 7815 if (new_space_strings_[i] == heap_->the_hole_value()) { 7816 continue; 7817 } 7818 ASSERT(new_space_strings_[i]->IsExternalString()); 7819 if (heap_->InNewSpace(new_space_strings_[i])) { 7820 new_space_strings_[last++] = new_space_strings_[i]; 7821 } else { 7822 old_space_strings_.Add(new_space_strings_[i]); 7823 } 7824 } 7825 new_space_strings_.Rewind(last); 7826 new_space_strings_.Trim(); 7827 7828 last = 0; 7829 for (int i = 0; i < old_space_strings_.length(); ++i) { 7830 if (old_space_strings_[i] == heap_->the_hole_value()) { 7831 continue; 7832 } 7833 ASSERT(old_space_strings_[i]->IsExternalString()); 7834 ASSERT(!heap_->InNewSpace(old_space_strings_[i])); 7835 old_space_strings_[last++] = old_space_strings_[i]; 7836 } 7837 old_space_strings_.Rewind(last); 7838 old_space_strings_.Trim(); 7839 #ifdef VERIFY_HEAP 7840 if (FLAG_verify_heap) { 7841 Verify(); 7842 } 7843 #endif 7844 } 7845 7846 7847 void ExternalStringTable::TearDown() { 7848 for (int i = 0; i < new_space_strings_.length(); ++i) { 7849 heap_->FinalizeExternalString(ExternalString::cast(new_space_strings_[i])); 7850 } 7851 new_space_strings_.Free(); 7852 for (int i = 0; i < old_space_strings_.length(); ++i) { 7853 heap_->FinalizeExternalString(ExternalString::cast(old_space_strings_[i])); 7854 } 7855 old_space_strings_.Free(); 7856 } 7857 7858 7859 void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) { 7860 chunk->set_next_chunk(chunks_queued_for_free_); 7861 chunks_queued_for_free_ = chunk; 7862 } 7863 7864 7865 void Heap::FreeQueuedChunks() { 7866 if (chunks_queued_for_free_ == NULL) return; 7867 MemoryChunk* next; 7868 MemoryChunk* chunk; 7869 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { 7870 next = chunk->next_chunk(); 7871 chunk->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED); 7872 7873 if (chunk->owner()->identity() == LO_SPACE) { 7874 // StoreBuffer::Filter relies on MemoryChunk::FromAnyPointerAddress. 7875 // If FromAnyPointerAddress encounters a slot that belongs to a large 7876 // chunk queued for deletion it will fail to find the chunk because 7877 // it try to perform a search in the list of pages owned by of the large 7878 // object space and queued chunks were detached from that list. 7879 // To work around this we split large chunk into normal kPageSize aligned 7880 // pieces and initialize size, owner and flags field of every piece. 7881 // If FromAnyPointerAddress encounters a slot that belongs to one of 7882 // these smaller pieces it will treat it as a slot on a normal Page. 7883 Address chunk_end = chunk->address() + chunk->size(); 7884 MemoryChunk* inner = MemoryChunk::FromAddress( 7885 chunk->address() + Page::kPageSize); 7886 MemoryChunk* inner_last = MemoryChunk::FromAddress(chunk_end - 1); 7887 while (inner <= inner_last) { 7888 // Size of a large chunk is always a multiple of 7889 // OS::AllocateAlignment() so there is always 7890 // enough space for a fake MemoryChunk header. 7891 Address area_end = Min(inner->address() + Page::kPageSize, chunk_end); 7892 // Guard against overflow. 7893 if (area_end < inner->address()) area_end = chunk_end; 7894 inner->SetArea(inner->address(), area_end); 7895 inner->set_size(Page::kPageSize); 7896 inner->set_owner(lo_space()); 7897 inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED); 7898 inner = MemoryChunk::FromAddress( 7899 inner->address() + Page::kPageSize); 7900 } 7901 } 7902 } 7903 isolate_->heap()->store_buffer()->Compact(); 7904 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED); 7905 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { 7906 next = chunk->next_chunk(); 7907 isolate_->memory_allocator()->Free(chunk); 7908 } 7909 chunks_queued_for_free_ = NULL; 7910 } 7911 7912 7913 void Heap::RememberUnmappedPage(Address page, bool compacted) { 7914 uintptr_t p = reinterpret_cast<uintptr_t>(page); 7915 // Tag the page pointer to make it findable in the dump file. 7916 if (compacted) { 7917 p ^= 0xc1ead & (Page::kPageSize - 1); // Cleared. 7918 } else { 7919 p ^= 0x1d1ed & (Page::kPageSize - 1); // I died. 7920 } 7921 remembered_unmapped_pages_[remembered_unmapped_pages_index_] = 7922 reinterpret_cast<Address>(p); 7923 remembered_unmapped_pages_index_++; 7924 remembered_unmapped_pages_index_ %= kRememberedUnmappedPages; 7925 } 7926 7927 7928 void Heap::ClearObjectStats(bool clear_last_time_stats) { 7929 memset(object_counts_, 0, sizeof(object_counts_)); 7930 memset(object_sizes_, 0, sizeof(object_sizes_)); 7931 if (clear_last_time_stats) { 7932 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_)); 7933 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_)); 7934 } 7935 } 7936 7937 7938 static LazyMutex checkpoint_object_stats_mutex = LAZY_MUTEX_INITIALIZER; 7939 7940 7941 void Heap::CheckpointObjectStats() { 7942 LockGuard<Mutex> lock_guard(checkpoint_object_stats_mutex.Pointer()); 7943 Counters* counters = isolate()->counters(); 7944 #define ADJUST_LAST_TIME_OBJECT_COUNT(name) \ 7945 counters->count_of_##name()->Increment( \ 7946 static_cast<int>(object_counts_[name])); \ 7947 counters->count_of_##name()->Decrement( \ 7948 static_cast<int>(object_counts_last_time_[name])); \ 7949 counters->size_of_##name()->Increment( \ 7950 static_cast<int>(object_sizes_[name])); \ 7951 counters->size_of_##name()->Decrement( \ 7952 static_cast<int>(object_sizes_last_time_[name])); 7953 INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT) 7954 #undef ADJUST_LAST_TIME_OBJECT_COUNT 7955 int index; 7956 #define ADJUST_LAST_TIME_OBJECT_COUNT(name) \ 7957 index = FIRST_CODE_KIND_SUB_TYPE + Code::name; \ 7958 counters->count_of_CODE_TYPE_##name()->Increment( \ 7959 static_cast<int>(object_counts_[index])); \ 7960 counters->count_of_CODE_TYPE_##name()->Decrement( \ 7961 static_cast<int>(object_counts_last_time_[index])); \ 7962 counters->size_of_CODE_TYPE_##name()->Increment( \ 7963 static_cast<int>(object_sizes_[index])); \ 7964 counters->size_of_CODE_TYPE_##name()->Decrement( \ 7965 static_cast<int>(object_sizes_last_time_[index])); 7966 CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT) 7967 #undef ADJUST_LAST_TIME_OBJECT_COUNT 7968 #define ADJUST_LAST_TIME_OBJECT_COUNT(name) \ 7969 index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \ 7970 counters->count_of_FIXED_ARRAY_##name()->Increment( \ 7971 static_cast<int>(object_counts_[index])); \ 7972 counters->count_of_FIXED_ARRAY_##name()->Decrement( \ 7973 static_cast<int>(object_counts_last_time_[index])); \ 7974 counters->size_of_FIXED_ARRAY_##name()->Increment( \ 7975 static_cast<int>(object_sizes_[index])); \ 7976 counters->size_of_FIXED_ARRAY_##name()->Decrement( \ 7977 static_cast<int>(object_sizes_last_time_[index])); 7978 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT) 7979 #undef ADJUST_LAST_TIME_OBJECT_COUNT 7980 #define ADJUST_LAST_TIME_OBJECT_COUNT(name) \ 7981 index = \ 7982 FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - Code::kFirstCodeAge; \ 7983 counters->count_of_CODE_AGE_##name()->Increment( \ 7984 static_cast<int>(object_counts_[index])); \ 7985 counters->count_of_CODE_AGE_##name()->Decrement( \ 7986 static_cast<int>(object_counts_last_time_[index])); \ 7987 counters->size_of_CODE_AGE_##name()->Increment( \ 7988 static_cast<int>(object_sizes_[index])); \ 7989 counters->size_of_CODE_AGE_##name()->Decrement( \ 7990 static_cast<int>(object_sizes_last_time_[index])); 7991 CODE_AGE_LIST_COMPLETE(ADJUST_LAST_TIME_OBJECT_COUNT) 7992 #undef ADJUST_LAST_TIME_OBJECT_COUNT 7993 7994 OS::MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_)); 7995 OS::MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_)); 7996 ClearObjectStats(); 7997 } 7998 7999 } } // namespace v8::internal 8000