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