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