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