• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/heap/heap.h"
6 
7 #include <unordered_map>
8 #include <unordered_set>
9 
10 #include "src/accessors.h"
11 #include "src/api-inl.h"
12 #include "src/assembler-inl.h"
13 #include "src/ast/context-slot-cache.h"
14 #include "src/base/bits.h"
15 #include "src/base/once.h"
16 #include "src/base/utils/random-number-generator.h"
17 #include "src/bootstrapper.h"
18 #include "src/code-stubs.h"
19 #include "src/compilation-cache.h"
20 #include "src/conversions.h"
21 #include "src/debug/debug.h"
22 #include "src/deoptimizer.h"
23 #include "src/feedback-vector.h"
24 #include "src/global-handles.h"
25 #include "src/heap/array-buffer-collector.h"
26 #include "src/heap/array-buffer-tracker-inl.h"
27 #include "src/heap/barrier.h"
28 #include "src/heap/code-stats.h"
29 #include "src/heap/concurrent-marking.h"
30 #include "src/heap/embedder-tracing.h"
31 #include "src/heap/gc-idle-time-handler.h"
32 #include "src/heap/gc-tracer.h"
33 #include "src/heap/heap-controller.h"
34 #include "src/heap/heap-write-barrier-inl.h"
35 #include "src/heap/incremental-marking.h"
36 #include "src/heap/item-parallel-job.h"
37 #include "src/heap/mark-compact-inl.h"
38 #include "src/heap/mark-compact.h"
39 #include "src/heap/memory-reducer.h"
40 #include "src/heap/object-stats.h"
41 #include "src/heap/objects-visiting-inl.h"
42 #include "src/heap/objects-visiting.h"
43 #include "src/heap/remembered-set.h"
44 #include "src/heap/scavenge-job.h"
45 #include "src/heap/scavenger-inl.h"
46 #include "src/heap/store-buffer.h"
47 #include "src/heap/stress-marking-observer.h"
48 #include "src/heap/stress-scavenge-observer.h"
49 #include "src/heap/sweeper.h"
50 #include "src/instruction-stream.h"
51 #include "src/interpreter/interpreter.h"
52 #include "src/objects/data-handler.h"
53 #include "src/objects/hash-table-inl.h"
54 #include "src/objects/maybe-object.h"
55 #include "src/objects/shared-function-info.h"
56 #include "src/regexp/jsregexp.h"
57 #include "src/runtime-profiler.h"
58 #include "src/snapshot/natives.h"
59 #include "src/snapshot/serializer-common.h"
60 #include "src/snapshot/snapshot.h"
61 #include "src/tracing/trace-event.h"
62 #include "src/unicode-decoder.h"
63 #include "src/unicode-inl.h"
64 #include "src/utils-inl.h"
65 #include "src/utils.h"
66 #include "src/v8.h"
67 #include "src/vm-state-inl.h"
68 
69 // Has to be the last include (doesn't have include guards):
70 #include "src/objects/object-macros.h"
71 
72 namespace v8 {
73 namespace internal {
74 
SetArgumentsAdaptorDeoptPCOffset(int pc_offset)75 void Heap::SetArgumentsAdaptorDeoptPCOffset(int pc_offset) {
76   DCHECK_EQ(Smi::kZero, arguments_adaptor_deopt_pc_offset());
77   set_arguments_adaptor_deopt_pc_offset(Smi::FromInt(pc_offset));
78 }
79 
SetConstructStubCreateDeoptPCOffset(int pc_offset)80 void Heap::SetConstructStubCreateDeoptPCOffset(int pc_offset) {
81   DCHECK(construct_stub_create_deopt_pc_offset() == Smi::kZero);
82   set_construct_stub_create_deopt_pc_offset(Smi::FromInt(pc_offset));
83 }
84 
SetConstructStubInvokeDeoptPCOffset(int pc_offset)85 void Heap::SetConstructStubInvokeDeoptPCOffset(int pc_offset) {
86   DCHECK(construct_stub_invoke_deopt_pc_offset() == Smi::kZero);
87   set_construct_stub_invoke_deopt_pc_offset(Smi::FromInt(pc_offset));
88 }
89 
SetInterpreterEntryReturnPCOffset(int pc_offset)90 void Heap::SetInterpreterEntryReturnPCOffset(int pc_offset) {
91   DCHECK_EQ(Smi::kZero, interpreter_entry_return_pc_offset());
92   set_interpreter_entry_return_pc_offset(Smi::FromInt(pc_offset));
93 }
94 
SetSerializedObjects(FixedArray * objects)95 void Heap::SetSerializedObjects(FixedArray* objects) {
96   DCHECK(isolate()->serializer_enabled());
97   set_serialized_objects(objects);
98 }
99 
SetSerializedGlobalProxySizes(FixedArray * sizes)100 void Heap::SetSerializedGlobalProxySizes(FixedArray* sizes) {
101   DCHECK(isolate()->serializer_enabled());
102   set_serialized_global_proxy_sizes(sizes);
103 }
104 
operator ==(const Heap::GCCallbackTuple & other) const105 bool Heap::GCCallbackTuple::operator==(
106     const Heap::GCCallbackTuple& other) const {
107   return other.callback == callback && other.data == data;
108 }
109 
operator =(const Heap::GCCallbackTuple & other)110 Heap::GCCallbackTuple& Heap::GCCallbackTuple::operator=(
111     const Heap::GCCallbackTuple& other) {
112   callback = other.callback;
113   gc_type = other.gc_type;
114   data = other.data;
115   return *this;
116 }
117 
118 struct Heap::StrongRootsList {
119   Object** start;
120   Object** end;
121   StrongRootsList* next;
122 };
123 
124 class IdleScavengeObserver : public AllocationObserver {
125  public:
IdleScavengeObserver(Heap & heap,intptr_t step_size)126   IdleScavengeObserver(Heap& heap, intptr_t step_size)
127       : AllocationObserver(step_size), heap_(heap) {}
128 
Step(int bytes_allocated,Address,size_t)129   void Step(int bytes_allocated, Address, size_t) override {
130     heap_.ScheduleIdleScavengeIfNeeded(bytes_allocated);
131   }
132 
133  private:
134   Heap& heap_;
135 };
136 
Heap()137 Heap::Heap()
138     : external_memory_(0),
139       external_memory_limit_(kExternalAllocationSoftLimit),
140       external_memory_at_last_mark_compact_(0),
141       external_memory_concurrently_freed_(0),
142       isolate_(nullptr),
143       code_range_size_(0),
144       // semispace_size_ should be a power of 2 and old_generation_size_ should
145       // be a multiple of Page::kPageSize.
146       max_semi_space_size_(8 * (kPointerSize / 4) * MB),
147       initial_semispace_size_(kMinSemiSpaceSizeInKB * KB),
148       max_old_generation_size_(700ul * (kPointerSize / 4) * MB),
149       initial_max_old_generation_size_(max_old_generation_size_),
150       initial_old_generation_size_(max_old_generation_size_ /
151                                    kInitalOldGenerationLimitFactor),
152       old_generation_size_configured_(false),
153       // Variables set based on semispace_size_ and old_generation_size_ in
154       // ConfigureHeap.
155       // Will be 4 * reserved_semispace_size_ to ensure that young
156       // generation can be aligned to its size.
157       maximum_committed_(0),
158       survived_since_last_expansion_(0),
159       survived_last_scavenge_(0),
160       always_allocate_scope_count_(0),
161       memory_pressure_level_(MemoryPressureLevel::kNone),
162       contexts_disposed_(0),
163       number_of_disposed_maps_(0),
164       new_space_(nullptr),
165       old_space_(nullptr),
166       code_space_(nullptr),
167       map_space_(nullptr),
168       lo_space_(nullptr),
169       new_lo_space_(nullptr),
170       read_only_space_(nullptr),
171       write_protect_code_memory_(false),
172       code_space_memory_modification_scope_depth_(0),
173       gc_state_(NOT_IN_GC),
174       gc_post_processing_depth_(0),
175       allocations_count_(0),
176       raw_allocations_hash_(0),
177       stress_marking_observer_(nullptr),
178       stress_scavenge_observer_(nullptr),
179       allocation_step_in_progress_(false),
180       max_marking_limit_reached_(0.0),
181       ms_count_(0),
182       gc_count_(0),
183       consecutive_ineffective_mark_compacts_(0),
184       mmap_region_base_(0),
185       remembered_unmapped_pages_index_(0),
186       old_generation_allocation_limit_(initial_old_generation_size_),
187       inline_allocation_disabled_(false),
188       tracer_(nullptr),
189       promoted_objects_size_(0),
190       promotion_ratio_(0),
191       semi_space_copied_object_size_(0),
192       previous_semi_space_copied_object_size_(0),
193       semi_space_copied_rate_(0),
194       nodes_died_in_new_space_(0),
195       nodes_copied_in_new_space_(0),
196       nodes_promoted_(0),
197       maximum_size_scavenges_(0),
198       last_idle_notification_time_(0.0),
199       last_gc_time_(0.0),
200       mark_compact_collector_(nullptr),
201       minor_mark_compact_collector_(nullptr),
202       array_buffer_collector_(nullptr),
203       memory_allocator_(nullptr),
204       store_buffer_(nullptr),
205       incremental_marking_(nullptr),
206       concurrent_marking_(nullptr),
207       gc_idle_time_handler_(nullptr),
208       memory_reducer_(nullptr),
209       live_object_stats_(nullptr),
210       dead_object_stats_(nullptr),
211       scavenge_job_(nullptr),
212       parallel_scavenge_semaphore_(0),
213       idle_scavenge_observer_(nullptr),
214       new_space_allocation_counter_(0),
215       old_generation_allocation_counter_at_last_gc_(0),
216       old_generation_size_at_last_gc_(0),
217       global_pretenuring_feedback_(kInitialFeedbackCapacity),
218       is_marking_flag_(false),
219       ring_buffer_full_(false),
220       ring_buffer_end_(0),
221       configured_(false),
222       current_gc_flags_(Heap::kNoGCFlags),
223       current_gc_callback_flags_(GCCallbackFlags::kNoGCCallbackFlags),
224       external_string_table_(this),
225       gc_callbacks_depth_(0),
226       deserialization_complete_(false),
227       strong_roots_list_(nullptr),
228       heap_iterator_depth_(0),
229       local_embedder_heap_tracer_(nullptr),
230       fast_promotion_mode_(false),
231       force_oom_(false),
232       delay_sweeper_tasks_for_testing_(false),
233       pending_layout_change_object_(nullptr),
234       unprotected_memory_chunks_registry_enabled_(false)
235 #ifdef V8_ENABLE_ALLOCATION_TIMEOUT
236       ,
237       allocation_timeout_(0)
238 #endif  // V8_ENABLE_ALLOCATION_TIMEOUT
239 {
240   // Ensure old_generation_size_ is a multiple of kPageSize.
241   DCHECK_EQ(0, max_old_generation_size_ & (Page::kPageSize - 1));
242 
243   memset(roots_, 0, sizeof(roots_[0]) * kRootListLength);
244   set_native_contexts_list(nullptr);
245   set_allocation_sites_list(Smi::kZero);
246   // Put a dummy entry in the remembered pages so we can find the list the
247   // minidump even if there are no real unmapped pages.
248   RememberUnmappedPage(kNullAddress, false);
249 }
250 
MaxReserved()251 size_t Heap::MaxReserved() {
252   const double kFactor = Page::kPageSize * 1.0 / Page::kAllocatableMemory;
253   return static_cast<size_t>(
254       (2 * max_semi_space_size_ + max_old_generation_size_) * kFactor);
255 }
256 
ComputeMaxOldGenerationSize(uint64_t physical_memory)257 size_t Heap::ComputeMaxOldGenerationSize(uint64_t physical_memory) {
258   const size_t old_space_physical_memory_factor = 4;
259   size_t computed_size = static_cast<size_t>(physical_memory / i::MB /
260                                              old_space_physical_memory_factor *
261                                              kPointerMultiplier);
262   return Max(Min(computed_size, HeapController::kMaxHeapSize),
263              HeapController::kMinHeapSize);
264 }
265 
Capacity()266 size_t Heap::Capacity() {
267   if (!HasBeenSetUp()) return 0;
268 
269   return new_space_->Capacity() + OldGenerationCapacity();
270 }
271 
OldGenerationCapacity()272 size_t Heap::OldGenerationCapacity() {
273   if (!HasBeenSetUp()) return 0;
274   PagedSpaces spaces(this, PagedSpaces::SpacesSpecifier::kAllPagedSpaces);
275   size_t total = 0;
276   for (PagedSpace* space = spaces.next(); space != nullptr;
277        space = spaces.next()) {
278     total += space->Capacity();
279   }
280   return total + lo_space_->SizeOfObjects();
281 }
282 
CommittedOldGenerationMemory()283 size_t Heap::CommittedOldGenerationMemory() {
284   if (!HasBeenSetUp()) return 0;
285 
286   PagedSpaces spaces(this, PagedSpaces::SpacesSpecifier::kAllPagedSpaces);
287   size_t total = 0;
288   for (PagedSpace* space = spaces.next(); space != nullptr;
289        space = spaces.next()) {
290     total += space->CommittedMemory();
291   }
292   return total + lo_space_->Size();
293 }
294 
CommittedMemoryOfHeapAndUnmapper()295 size_t Heap::CommittedMemoryOfHeapAndUnmapper() {
296   if (!HasBeenSetUp()) return 0;
297 
298   return CommittedMemory() +
299          memory_allocator()->unmapper()->CommittedBufferedMemory();
300 }
301 
CommittedMemory()302 size_t Heap::CommittedMemory() {
303   if (!HasBeenSetUp()) return 0;
304 
305   return new_space_->CommittedMemory() + CommittedOldGenerationMemory();
306 }
307 
308 
CommittedPhysicalMemory()309 size_t Heap::CommittedPhysicalMemory() {
310   if (!HasBeenSetUp()) return 0;
311 
312   size_t total = 0;
313   for (SpaceIterator it(this); it.has_next();) {
314     total += it.next()->CommittedPhysicalMemory();
315   }
316 
317   return total;
318 }
319 
CommittedMemoryExecutable()320 size_t Heap::CommittedMemoryExecutable() {
321   if (!HasBeenSetUp()) return 0;
322 
323   return static_cast<size_t>(memory_allocator()->SizeExecutable());
324 }
325 
326 
UpdateMaximumCommitted()327 void Heap::UpdateMaximumCommitted() {
328   if (!HasBeenSetUp()) return;
329 
330   const size_t current_committed_memory = CommittedMemory();
331   if (current_committed_memory > maximum_committed_) {
332     maximum_committed_ = current_committed_memory;
333   }
334 }
335 
Available()336 size_t Heap::Available() {
337   if (!HasBeenSetUp()) return 0;
338 
339   size_t total = 0;
340 
341   for (SpaceIterator it(this); it.has_next();) {
342     total += it.next()->Available();
343   }
344   return total;
345 }
346 
CanExpandOldGeneration(size_t size)347 bool Heap::CanExpandOldGeneration(size_t size) {
348   if (force_oom_) return false;
349   if (OldGenerationCapacity() + size > MaxOldGenerationSize()) return false;
350   // The OldGenerationCapacity does not account compaction spaces used
351   // during evacuation. Ensure that expanding the old generation does push
352   // the total allocated memory size over the maximum heap size.
353   return memory_allocator()->Size() + size <= MaxReserved();
354 }
355 
HasBeenSetUp()356 bool Heap::HasBeenSetUp() {
357   // We will always have a new space when the heap is set up.
358   return new_space_ != nullptr;
359 }
360 
361 
SelectGarbageCollector(AllocationSpace space,const char ** reason)362 GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space,
363                                               const char** reason) {
364   // Is global GC requested?
365   if (space != NEW_SPACE) {
366     isolate_->counters()->gc_compactor_caused_by_request()->Increment();
367     *reason = "GC in old space requested";
368     return MARK_COMPACTOR;
369   }
370 
371   if (FLAG_gc_global || (FLAG_stress_compaction && (gc_count_ & 1) != 0)) {
372     *reason = "GC in old space forced by flags";
373     return MARK_COMPACTOR;
374   }
375 
376   if (incremental_marking()->NeedsFinalization() &&
377       AllocationLimitOvershotByLargeMargin()) {
378     *reason = "Incremental marking needs finalization";
379     return MARK_COMPACTOR;
380   }
381 
382   // Over-estimate the new space size using capacity to allow some slack.
383   if (!CanExpandOldGeneration(new_space_->TotalCapacity())) {
384     isolate_->counters()
385         ->gc_compactor_caused_by_oldspace_exhaustion()
386         ->Increment();
387     *reason = "scavenge might not succeed";
388     return MARK_COMPACTOR;
389   }
390 
391   // Default
392   *reason = nullptr;
393   return YoungGenerationCollector();
394 }
395 
SetGCState(HeapState state)396 void Heap::SetGCState(HeapState state) {
397   gc_state_ = state;
398 }
399 
PrintShortHeapStatistics()400 void Heap::PrintShortHeapStatistics() {
401   if (!FLAG_trace_gc_verbose) return;
402   PrintIsolate(isolate_,
403                "Memory allocator,       used: %6" PRIuS
404                " KB,"
405                " available: %6" PRIuS " KB\n",
406                memory_allocator()->Size() / KB,
407                memory_allocator()->Available() / KB);
408   PrintIsolate(isolate_,
409                "Read-only space,        used: %6" PRIuS
410                " KB"
411                ", available: %6" PRIuS
412                " KB"
413                ", committed: %6" PRIuS " KB\n",
414                read_only_space_->Size() / KB,
415                read_only_space_->Available() / KB,
416                read_only_space_->CommittedMemory() / KB);
417   PrintIsolate(isolate_,
418                "New space,              used: %6" PRIuS
419                " KB"
420                ", available: %6" PRIuS
421                " KB"
422                ", committed: %6" PRIuS " KB\n",
423                new_space_->Size() / KB, new_space_->Available() / KB,
424                new_space_->CommittedMemory() / KB);
425   PrintIsolate(isolate_,
426                "New large object space, used: %6" PRIuS
427                " KB"
428                ", available: %6" PRIuS
429                " KB"
430                ", committed: %6" PRIuS " KB\n",
431                new_lo_space_->SizeOfObjects() / KB,
432                new_lo_space_->Available() / KB,
433                new_lo_space_->CommittedMemory() / KB);
434   PrintIsolate(isolate_,
435                "Old space,              used: %6" PRIuS
436                " KB"
437                ", available: %6" PRIuS
438                " KB"
439                ", committed: %6" PRIuS " KB\n",
440                old_space_->SizeOfObjects() / KB, old_space_->Available() / KB,
441                old_space_->CommittedMemory() / KB);
442   PrintIsolate(isolate_,
443                "Code space,             used: %6" PRIuS
444                " KB"
445                ", available: %6" PRIuS
446                " KB"
447                ", committed: %6" PRIuS "KB\n",
448                code_space_->SizeOfObjects() / KB, code_space_->Available() / KB,
449                code_space_->CommittedMemory() / KB);
450   PrintIsolate(isolate_,
451                "Map space,              used: %6" PRIuS
452                " KB"
453                ", available: %6" PRIuS
454                " KB"
455                ", committed: %6" PRIuS " KB\n",
456                map_space_->SizeOfObjects() / KB, map_space_->Available() / KB,
457                map_space_->CommittedMemory() / KB);
458   PrintIsolate(isolate_,
459                "Large object space,     used: %6" PRIuS
460                " KB"
461                ", available: %6" PRIuS
462                " KB"
463                ", committed: %6" PRIuS " KB\n",
464                lo_space_->SizeOfObjects() / KB, lo_space_->Available() / KB,
465                lo_space_->CommittedMemory() / KB);
466   PrintIsolate(isolate_,
467                "All spaces,             used: %6" PRIuS
468                " KB"
469                ", available: %6" PRIuS
470                " KB"
471                ", committed: %6" PRIuS "KB\n",
472                this->SizeOfObjects() / KB, this->Available() / KB,
473                this->CommittedMemory() / KB);
474   PrintIsolate(isolate_,
475                "Unmapper buffering %d chunks of committed: %6" PRIuS " KB\n",
476                memory_allocator()->unmapper()->NumberOfChunks(),
477                CommittedMemoryOfHeapAndUnmapper() / KB);
478   PrintIsolate(isolate_, "External memory reported: %6" PRId64 " KB\n",
479                external_memory_ / KB);
480   PrintIsolate(isolate_, "External memory global %zu KB\n",
481                external_memory_callback_() / KB);
482   PrintIsolate(isolate_, "Total time spent in GC  : %.1f ms\n",
483                total_gc_time_ms_);
484 }
485 
ReportStatisticsAfterGC()486 void Heap::ReportStatisticsAfterGC() {
487   for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount);
488        ++i) {
489     int count = deferred_counters_[i];
490     deferred_counters_[i] = 0;
491     while (count > 0) {
492       count--;
493       isolate()->CountUsage(static_cast<v8::Isolate::UseCounterFeature>(i));
494     }
495   }
496 }
497 
AddHeapObjectAllocationTracker(HeapObjectAllocationTracker * tracker)498 void Heap::AddHeapObjectAllocationTracker(
499     HeapObjectAllocationTracker* tracker) {
500   if (allocation_trackers_.empty()) DisableInlineAllocation();
501   allocation_trackers_.push_back(tracker);
502 }
503 
RemoveHeapObjectAllocationTracker(HeapObjectAllocationTracker * tracker)504 void Heap::RemoveHeapObjectAllocationTracker(
505     HeapObjectAllocationTracker* tracker) {
506   allocation_trackers_.erase(std::remove(allocation_trackers_.begin(),
507                                          allocation_trackers_.end(), tracker),
508                              allocation_trackers_.end());
509   if (allocation_trackers_.empty()) EnableInlineAllocation();
510 }
511 
AddRetainingPathTarget(Handle<HeapObject> object,RetainingPathOption option)512 void Heap::AddRetainingPathTarget(Handle<HeapObject> object,
513                                   RetainingPathOption option) {
514   if (!FLAG_track_retaining_path) {
515     PrintF("Retaining path tracking requires --track-retaining-path\n");
516   } else {
517     Handle<WeakArrayList> array(retaining_path_targets(), isolate());
518     int index = array->length();
519     array = WeakArrayList::AddToEnd(isolate(), array,
520                                     MaybeObjectHandle::Weak(object));
521     set_retaining_path_targets(*array);
522     DCHECK_EQ(array->length(), index + 1);
523     retaining_path_target_option_[index] = option;
524   }
525 }
526 
IsRetainingPathTarget(HeapObject * object,RetainingPathOption * option)527 bool Heap::IsRetainingPathTarget(HeapObject* object,
528                                  RetainingPathOption* option) {
529   WeakArrayList* targets = retaining_path_targets();
530   int length = targets->length();
531   MaybeObject* object_to_check = HeapObjectReference::Weak(object);
532   for (int i = 0; i < length; i++) {
533     MaybeObject* target = targets->Get(i);
534     DCHECK(target->IsWeakOrClearedHeapObject());
535     if (target == object_to_check) {
536       DCHECK(retaining_path_target_option_.count(i));
537       *option = retaining_path_target_option_[i];
538       return true;
539     }
540   }
541   return false;
542 }
543 
PrintRetainingPath(HeapObject * target,RetainingPathOption option)544 void Heap::PrintRetainingPath(HeapObject* target, RetainingPathOption option) {
545   PrintF("\n\n\n");
546   PrintF("#################################################\n");
547   PrintF("Retaining path for %p:\n", static_cast<void*>(target));
548   HeapObject* object = target;
549   std::vector<std::pair<HeapObject*, bool>> retaining_path;
550   Root root = Root::kUnknown;
551   bool ephemeron = false;
552   while (true) {
553     retaining_path.push_back(std::make_pair(object, ephemeron));
554     if (option == RetainingPathOption::kTrackEphemeronPath &&
555         ephemeron_retainer_.count(object)) {
556       object = ephemeron_retainer_[object];
557       ephemeron = true;
558     } else if (retainer_.count(object)) {
559       object = retainer_[object];
560       ephemeron = false;
561     } else {
562       if (retaining_root_.count(object)) {
563         root = retaining_root_[object];
564       }
565       break;
566     }
567   }
568   int distance = static_cast<int>(retaining_path.size());
569   for (auto node : retaining_path) {
570     HeapObject* object = node.first;
571     bool ephemeron = node.second;
572     PrintF("\n");
573     PrintF("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
574     PrintF("Distance from root %d%s: ", distance,
575            ephemeron ? " (ephemeron)" : "");
576     object->ShortPrint();
577     PrintF("\n");
578 #ifdef OBJECT_PRINT
579     object->Print();
580     PrintF("\n");
581 #endif
582     --distance;
583   }
584   PrintF("\n");
585   PrintF("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
586   PrintF("Root: %s\n", RootVisitor::RootName(root));
587   PrintF("-------------------------------------------------\n");
588 }
589 
AddRetainer(HeapObject * retainer,HeapObject * object)590 void Heap::AddRetainer(HeapObject* retainer, HeapObject* object) {
591   if (retainer_.count(object)) return;
592   retainer_[object] = retainer;
593   RetainingPathOption option = RetainingPathOption::kDefault;
594   if (IsRetainingPathTarget(object, &option)) {
595     // Check if the retaining path was already printed in
596     // AddEphemeronRetainer().
597     if (ephemeron_retainer_.count(object) == 0 ||
598         option == RetainingPathOption::kDefault) {
599       PrintRetainingPath(object, option);
600     }
601   }
602 }
603 
AddEphemeronRetainer(HeapObject * retainer,HeapObject * object)604 void Heap::AddEphemeronRetainer(HeapObject* retainer, HeapObject* object) {
605   if (ephemeron_retainer_.count(object)) return;
606   ephemeron_retainer_[object] = retainer;
607   RetainingPathOption option = RetainingPathOption::kDefault;
608   if (IsRetainingPathTarget(object, &option) &&
609       option == RetainingPathOption::kTrackEphemeronPath) {
610     // Check if the retaining path was already printed in AddRetainer().
611     if (retainer_.count(object) == 0) {
612       PrintRetainingPath(object, option);
613     }
614   }
615 }
616 
AddRetainingRoot(Root root,HeapObject * object)617 void Heap::AddRetainingRoot(Root root, HeapObject* object) {
618   if (retaining_root_.count(object)) return;
619   retaining_root_[object] = root;
620   RetainingPathOption option = RetainingPathOption::kDefault;
621   if (IsRetainingPathTarget(object, &option)) {
622     PrintRetainingPath(object, option);
623   }
624 }
625 
IncrementDeferredCount(v8::Isolate::UseCounterFeature feature)626 void Heap::IncrementDeferredCount(v8::Isolate::UseCounterFeature feature) {
627   deferred_counters_[feature]++;
628 }
629 
UncommitFromSpace()630 bool Heap::UncommitFromSpace() { return new_space_->UncommitFromSpace(); }
631 
GarbageCollectionPrologue()632 void Heap::GarbageCollectionPrologue() {
633   TRACE_GC(tracer(), GCTracer::Scope::HEAP_PROLOGUE);
634   {
635     AllowHeapAllocation for_the_first_part_of_prologue;
636     gc_count_++;
637 
638 #ifdef VERIFY_HEAP
639     if (FLAG_verify_heap) {
640       Verify();
641     }
642 #endif
643   }
644 
645   // Reset GC statistics.
646   promoted_objects_size_ = 0;
647   previous_semi_space_copied_object_size_ = semi_space_copied_object_size_;
648   semi_space_copied_object_size_ = 0;
649   nodes_died_in_new_space_ = 0;
650   nodes_copied_in_new_space_ = 0;
651   nodes_promoted_ = 0;
652 
653   UpdateMaximumCommitted();
654 
655 #ifdef DEBUG
656   DCHECK(!AllowHeapAllocation::IsAllowed() && gc_state_ == NOT_IN_GC);
657 
658   if (FLAG_gc_verbose) Print();
659 #endif  // DEBUG
660 
661   if (new_space_->IsAtMaximumCapacity()) {
662     maximum_size_scavenges_++;
663   } else {
664     maximum_size_scavenges_ = 0;
665   }
666   CheckNewSpaceExpansionCriteria();
667   UpdateNewSpaceAllocationCounter();
668   if (FLAG_track_retaining_path) {
669     retainer_.clear();
670     ephemeron_retainer_.clear();
671     retaining_root_.clear();
672   }
673 }
674 
SizeOfObjects()675 size_t Heap::SizeOfObjects() {
676   size_t total = 0;
677 
678   for (SpaceIterator it(this); it.has_next();) {
679     total += it.next()->SizeOfObjects();
680   }
681   return total;
682 }
683 
684 
GetSpaceName(int idx)685 const char* Heap::GetSpaceName(int idx) {
686   switch (idx) {
687     case NEW_SPACE:
688       return "new_space";
689     case OLD_SPACE:
690       return "old_space";
691     case MAP_SPACE:
692       return "map_space";
693     case CODE_SPACE:
694       return "code_space";
695     case LO_SPACE:
696       return "large_object_space";
697     case NEW_LO_SPACE:
698       return "new_large_object_space";
699     case RO_SPACE:
700       return "read_only_space";
701     default:
702       UNREACHABLE();
703   }
704   return nullptr;
705 }
706 
SetRootCodeStubs(SimpleNumberDictionary * value)707 void Heap::SetRootCodeStubs(SimpleNumberDictionary* value) {
708   roots_[kCodeStubsRootIndex] = value;
709 }
710 
RepairFreeListsAfterDeserialization()711 void Heap::RepairFreeListsAfterDeserialization() {
712   PagedSpaces spaces(this);
713   for (PagedSpace* space = spaces.next(); space != nullptr;
714        space = spaces.next()) {
715     space->RepairFreeListsAfterDeserialization();
716   }
717 }
718 
MergeAllocationSitePretenuringFeedback(const PretenuringFeedbackMap & local_pretenuring_feedback)719 void Heap::MergeAllocationSitePretenuringFeedback(
720     const PretenuringFeedbackMap& local_pretenuring_feedback) {
721   AllocationSite* site = nullptr;
722   for (auto& site_and_count : local_pretenuring_feedback) {
723     site = site_and_count.first;
724     MapWord map_word = site_and_count.first->map_word();
725     if (map_word.IsForwardingAddress()) {
726       site = AllocationSite::cast(map_word.ToForwardingAddress());
727     }
728 
729     // We have not validated the allocation site yet, since we have not
730     // dereferenced the site during collecting information.
731     // This is an inlined check of AllocationMemento::IsValid.
732     if (!site->IsAllocationSite() || site->IsZombie()) continue;
733 
734     const int value = static_cast<int>(site_and_count.second);
735     DCHECK_LT(0, value);
736     if (site->IncrementMementoFoundCount(value)) {
737       // For sites in the global map the count is accessed through the site.
738       global_pretenuring_feedback_.insert(std::make_pair(site, 0));
739     }
740   }
741 }
742 
AddAllocationObserversToAllSpaces(AllocationObserver * observer,AllocationObserver * new_space_observer)743 void Heap::AddAllocationObserversToAllSpaces(
744     AllocationObserver* observer, AllocationObserver* new_space_observer) {
745   DCHECK(observer && new_space_observer);
746 
747   for (SpaceIterator it(this); it.has_next();) {
748     Space* space = it.next();
749     if (space == new_space()) {
750       space->AddAllocationObserver(new_space_observer);
751     } else {
752       space->AddAllocationObserver(observer);
753     }
754   }
755 }
756 
RemoveAllocationObserversFromAllSpaces(AllocationObserver * observer,AllocationObserver * new_space_observer)757 void Heap::RemoveAllocationObserversFromAllSpaces(
758     AllocationObserver* observer, AllocationObserver* new_space_observer) {
759   DCHECK(observer && new_space_observer);
760 
761   for (SpaceIterator it(this); it.has_next();) {
762     Space* space = it.next();
763     if (space == new_space()) {
764       space->RemoveAllocationObserver(new_space_observer);
765     } else {
766       space->RemoveAllocationObserver(observer);
767     }
768   }
769 }
770 
771 class Heap::SkipStoreBufferScope {
772  public:
SkipStoreBufferScope(StoreBuffer * store_buffer)773   explicit SkipStoreBufferScope(StoreBuffer* store_buffer)
774       : store_buffer_(store_buffer) {
775     store_buffer_->MoveAllEntriesToRememberedSet();
776     store_buffer_->SetMode(StoreBuffer::IN_GC);
777   }
778 
~SkipStoreBufferScope()779   ~SkipStoreBufferScope() {
780     DCHECK(store_buffer_->Empty());
781     store_buffer_->SetMode(StoreBuffer::NOT_IN_GC);
782   }
783 
784  private:
785   StoreBuffer* store_buffer_;
786 };
787 
788 namespace {
MakePretenureDecision(AllocationSite * site,AllocationSite::PretenureDecision current_decision,double ratio,bool maximum_size_scavenge)789 inline bool MakePretenureDecision(
790     AllocationSite* site, AllocationSite::PretenureDecision current_decision,
791     double ratio, bool maximum_size_scavenge) {
792   // Here we just allow state transitions from undecided or maybe tenure
793   // to don't tenure, maybe tenure, or tenure.
794   if ((current_decision == AllocationSite::kUndecided ||
795        current_decision == AllocationSite::kMaybeTenure)) {
796     if (ratio >= AllocationSite::kPretenureRatio) {
797       // We just transition into tenure state when the semi-space was at
798       // maximum capacity.
799       if (maximum_size_scavenge) {
800         site->set_deopt_dependent_code(true);
801         site->set_pretenure_decision(AllocationSite::kTenure);
802         // Currently we just need to deopt when we make a state transition to
803         // tenure.
804         return true;
805       }
806       site->set_pretenure_decision(AllocationSite::kMaybeTenure);
807     } else {
808       site->set_pretenure_decision(AllocationSite::kDontTenure);
809     }
810   }
811   return false;
812 }
813 
DigestPretenuringFeedback(Isolate * isolate,AllocationSite * site,bool maximum_size_scavenge)814 inline bool DigestPretenuringFeedback(Isolate* isolate, AllocationSite* site,
815                                       bool maximum_size_scavenge) {
816   bool deopt = false;
817   int create_count = site->memento_create_count();
818   int found_count = site->memento_found_count();
819   bool minimum_mementos_created =
820       create_count >= AllocationSite::kPretenureMinimumCreated;
821   double ratio = minimum_mementos_created || FLAG_trace_pretenuring_statistics
822                      ? static_cast<double>(found_count) / create_count
823                      : 0.0;
824   AllocationSite::PretenureDecision current_decision =
825       site->pretenure_decision();
826 
827   if (minimum_mementos_created) {
828     deopt = MakePretenureDecision(site, current_decision, ratio,
829                                   maximum_size_scavenge);
830   }
831 
832   if (FLAG_trace_pretenuring_statistics) {
833     PrintIsolate(isolate,
834                  "pretenuring: AllocationSite(%p): (created, found, ratio) "
835                  "(%d, %d, %f) %s => %s\n",
836                  static_cast<void*>(site), create_count, found_count, ratio,
837                  site->PretenureDecisionName(current_decision),
838                  site->PretenureDecisionName(site->pretenure_decision()));
839   }
840 
841   // Clear feedback calculation fields until the next gc.
842   site->set_memento_found_count(0);
843   site->set_memento_create_count(0);
844   return deopt;
845 }
846 }  // namespace
847 
RemoveAllocationSitePretenuringFeedback(AllocationSite * site)848 void Heap::RemoveAllocationSitePretenuringFeedback(AllocationSite* site) {
849   global_pretenuring_feedback_.erase(site);
850 }
851 
DeoptMaybeTenuredAllocationSites()852 bool Heap::DeoptMaybeTenuredAllocationSites() {
853   return new_space_->IsAtMaximumCapacity() && maximum_size_scavenges_ == 0;
854 }
855 
ProcessPretenuringFeedback()856 void Heap::ProcessPretenuringFeedback() {
857   bool trigger_deoptimization = false;
858   if (FLAG_allocation_site_pretenuring) {
859     int tenure_decisions = 0;
860     int dont_tenure_decisions = 0;
861     int allocation_mementos_found = 0;
862     int allocation_sites = 0;
863     int active_allocation_sites = 0;
864 
865     AllocationSite* site = nullptr;
866 
867     // Step 1: Digest feedback for recorded allocation sites.
868     bool maximum_size_scavenge = MaximumSizeScavenge();
869     for (auto& site_and_count : global_pretenuring_feedback_) {
870       allocation_sites++;
871       site = site_and_count.first;
872       // Count is always access through the site.
873       DCHECK_EQ(0, site_and_count.second);
874       int found_count = site->memento_found_count();
875       // An entry in the storage does not imply that the count is > 0 because
876       // allocation sites might have been reset due to too many objects dying
877       // in old space.
878       if (found_count > 0) {
879         DCHECK(site->IsAllocationSite());
880         active_allocation_sites++;
881         allocation_mementos_found += found_count;
882         if (DigestPretenuringFeedback(isolate_, site, maximum_size_scavenge)) {
883           trigger_deoptimization = true;
884         }
885         if (site->GetPretenureMode() == TENURED) {
886           tenure_decisions++;
887         } else {
888           dont_tenure_decisions++;
889         }
890       }
891     }
892 
893     // Step 2: Deopt maybe tenured allocation sites if necessary.
894     bool deopt_maybe_tenured = DeoptMaybeTenuredAllocationSites();
895     if (deopt_maybe_tenured) {
896       ForeachAllocationSite(
897           allocation_sites_list(),
898           [&allocation_sites, &trigger_deoptimization](AllocationSite* site) {
899             DCHECK(site->IsAllocationSite());
900             allocation_sites++;
901             if (site->IsMaybeTenure()) {
902               site->set_deopt_dependent_code(true);
903               trigger_deoptimization = true;
904             }
905           });
906     }
907 
908     if (trigger_deoptimization) {
909       isolate_->stack_guard()->RequestDeoptMarkedAllocationSites();
910     }
911 
912     if (FLAG_trace_pretenuring_statistics &&
913         (allocation_mementos_found > 0 || tenure_decisions > 0 ||
914          dont_tenure_decisions > 0)) {
915       PrintIsolate(isolate(),
916                    "pretenuring: deopt_maybe_tenured=%d visited_sites=%d "
917                    "active_sites=%d "
918                    "mementos=%d tenured=%d not_tenured=%d\n",
919                    deopt_maybe_tenured ? 1 : 0, allocation_sites,
920                    active_allocation_sites, allocation_mementos_found,
921                    tenure_decisions, dont_tenure_decisions);
922     }
923 
924     global_pretenuring_feedback_.clear();
925     global_pretenuring_feedback_.reserve(kInitialFeedbackCapacity);
926   }
927 }
928 
InvalidateCodeEmbeddedObjects(Code * code)929 void Heap::InvalidateCodeEmbeddedObjects(Code* code) {
930   MemoryChunk* chunk = MemoryChunk::FromAddress(code->address());
931   CodePageMemoryModificationScope modification_scope(chunk);
932   code->InvalidateEmbeddedObjects(this);
933 }
934 
InvalidateCodeDeoptimizationData(Code * code)935 void Heap::InvalidateCodeDeoptimizationData(Code* code) {
936   MemoryChunk* chunk = MemoryChunk::FromAddress(code->address());
937   CodePageMemoryModificationScope modification_scope(chunk);
938   code->set_deoptimization_data(ReadOnlyRoots(this).empty_fixed_array());
939 }
940 
DeoptMarkedAllocationSites()941 void Heap::DeoptMarkedAllocationSites() {
942   // TODO(hpayer): If iterating over the allocation sites list becomes a
943   // performance issue, use a cache data structure in heap instead.
944 
945   ForeachAllocationSite(allocation_sites_list(), [this](AllocationSite* site) {
946     if (site->deopt_dependent_code()) {
947       site->dependent_code()->MarkCodeForDeoptimization(
948           isolate_, DependentCode::kAllocationSiteTenuringChangedGroup);
949       site->set_deopt_dependent_code(false);
950     }
951   });
952 
953   Deoptimizer::DeoptimizeMarkedCode(isolate_);
954 }
955 
956 
GarbageCollectionEpilogue()957 void Heap::GarbageCollectionEpilogue() {
958   TRACE_GC(tracer(), GCTracer::Scope::HEAP_EPILOGUE);
959   if (Heap::ShouldZapGarbage() || FLAG_clear_free_memory) {
960     ZapFromSpace();
961   }
962 
963 #ifdef VERIFY_HEAP
964   if (FLAG_verify_heap) {
965     Verify();
966   }
967 #endif
968 
969   AllowHeapAllocation for_the_rest_of_the_epilogue;
970 
971 #ifdef DEBUG
972   if (FLAG_print_global_handles) isolate_->global_handles()->Print();
973   if (FLAG_print_handles) PrintHandles();
974   if (FLAG_gc_verbose) Print();
975   if (FLAG_code_stats) ReportCodeStatistics("After GC");
976   if (FLAG_check_handle_count) CheckHandleCount();
977 #endif
978 
979   UpdateMaximumCommitted();
980 
981   isolate_->counters()->alive_after_last_gc()->Set(
982       static_cast<int>(SizeOfObjects()));
983 
984   isolate_->counters()->string_table_capacity()->Set(
985       string_table()->Capacity());
986   isolate_->counters()->number_of_symbols()->Set(
987       string_table()->NumberOfElements());
988 
989   if (CommittedMemory() > 0) {
990     isolate_->counters()->external_fragmentation_total()->AddSample(
991         static_cast<int>(100 - (SizeOfObjects() * 100.0) / CommittedMemory()));
992 
993     isolate_->counters()->heap_sample_total_committed()->AddSample(
994         static_cast<int>(CommittedMemory() / KB));
995     isolate_->counters()->heap_sample_total_used()->AddSample(
996         static_cast<int>(SizeOfObjects() / KB));
997     isolate_->counters()->heap_sample_map_space_committed()->AddSample(
998         static_cast<int>(map_space()->CommittedMemory() / KB));
999     isolate_->counters()->heap_sample_code_space_committed()->AddSample(
1000         static_cast<int>(code_space()->CommittedMemory() / KB));
1001 
1002     isolate_->counters()->heap_sample_maximum_committed()->AddSample(
1003         static_cast<int>(MaximumCommittedMemory() / KB));
1004   }
1005 
1006 #define UPDATE_COUNTERS_FOR_SPACE(space)                \
1007   isolate_->counters()->space##_bytes_available()->Set( \
1008       static_cast<int>(space()->Available()));          \
1009   isolate_->counters()->space##_bytes_committed()->Set( \
1010       static_cast<int>(space()->CommittedMemory()));    \
1011   isolate_->counters()->space##_bytes_used()->Set(      \
1012       static_cast<int>(space()->SizeOfObjects()));
1013 #define UPDATE_FRAGMENTATION_FOR_SPACE(space)                          \
1014   if (space()->CommittedMemory() > 0) {                                \
1015     isolate_->counters()->external_fragmentation_##space()->AddSample( \
1016         static_cast<int>(100 -                                         \
1017                          (space()->SizeOfObjects() * 100.0) /          \
1018                              space()->CommittedMemory()));             \
1019   }
1020 #define UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(space) \
1021   UPDATE_COUNTERS_FOR_SPACE(space)                         \
1022   UPDATE_FRAGMENTATION_FOR_SPACE(space)
1023 
1024   UPDATE_COUNTERS_FOR_SPACE(new_space)
1025   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_space)
1026   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(code_space)
1027   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(map_space)
1028   UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(lo_space)
1029 #undef UPDATE_COUNTERS_FOR_SPACE
1030 #undef UPDATE_FRAGMENTATION_FOR_SPACE
1031 #undef UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE
1032 
1033 #ifdef DEBUG
1034   ReportStatisticsAfterGC();
1035 #endif  // DEBUG
1036 
1037   last_gc_time_ = MonotonicallyIncreasingTimeInMs();
1038 
1039   {
1040     TRACE_GC(tracer(), GCTracer::Scope::HEAP_EPILOGUE_REDUCE_NEW_SPACE);
1041     ReduceNewSpaceSize();
1042   }
1043 }
1044 
1045 class GCCallbacksScope {
1046  public:
GCCallbacksScope(Heap * heap)1047   explicit GCCallbacksScope(Heap* heap) : heap_(heap) {
1048     heap_->gc_callbacks_depth_++;
1049   }
~GCCallbacksScope()1050   ~GCCallbacksScope() { heap_->gc_callbacks_depth_--; }
1051 
CheckReenter()1052   bool CheckReenter() { return heap_->gc_callbacks_depth_ == 1; }
1053 
1054  private:
1055   Heap* heap_;
1056 };
1057 
1058 
HandleGCRequest()1059 void Heap::HandleGCRequest() {
1060   if (FLAG_stress_scavenge > 0 && stress_scavenge_observer_->HasRequestedGC()) {
1061     CollectAllGarbage(NEW_SPACE, GarbageCollectionReason::kTesting);
1062     stress_scavenge_observer_->RequestedGCDone();
1063   } else if (HighMemoryPressure()) {
1064     incremental_marking()->reset_request_type();
1065     CheckMemoryPressure();
1066   } else if (incremental_marking()->request_type() ==
1067              IncrementalMarking::COMPLETE_MARKING) {
1068     incremental_marking()->reset_request_type();
1069     CollectAllGarbage(current_gc_flags_,
1070                       GarbageCollectionReason::kFinalizeMarkingViaStackGuard,
1071                       current_gc_callback_flags_);
1072   } else if (incremental_marking()->request_type() ==
1073                  IncrementalMarking::FINALIZATION &&
1074              incremental_marking()->IsMarking() &&
1075              !incremental_marking()->finalize_marking_completed()) {
1076     incremental_marking()->reset_request_type();
1077     FinalizeIncrementalMarkingIncrementally(
1078         GarbageCollectionReason::kFinalizeMarkingViaStackGuard);
1079   }
1080 }
1081 
1082 
ScheduleIdleScavengeIfNeeded(int bytes_allocated)1083 void Heap::ScheduleIdleScavengeIfNeeded(int bytes_allocated) {
1084   scavenge_job_->ScheduleIdleTaskIfNeeded(this, bytes_allocated);
1085 }
1086 
GCTypePriorityTimer(GarbageCollector collector)1087 HistogramTimer* Heap::GCTypePriorityTimer(GarbageCollector collector) {
1088   if (IsYoungGenerationCollector(collector)) {
1089     if (isolate_->IsIsolateInBackground()) {
1090       return isolate_->counters()->gc_scavenger_background();
1091     }
1092     return isolate_->counters()->gc_scavenger_foreground();
1093   } else {
1094     if (!incremental_marking()->IsStopped()) {
1095       if (ShouldReduceMemory()) {
1096         if (isolate_->IsIsolateInBackground()) {
1097           return isolate_->counters()->gc_finalize_reduce_memory_background();
1098         }
1099         return isolate_->counters()->gc_finalize_reduce_memory_foreground();
1100       } else {
1101         if (isolate_->IsIsolateInBackground()) {
1102           return isolate_->counters()->gc_finalize_background();
1103         }
1104         return isolate_->counters()->gc_finalize_foreground();
1105       }
1106     } else {
1107       if (isolate_->IsIsolateInBackground()) {
1108         return isolate_->counters()->gc_compactor_background();
1109       }
1110       return isolate_->counters()->gc_compactor_foreground();
1111     }
1112   }
1113 }
1114 
GCTypeTimer(GarbageCollector collector)1115 HistogramTimer* Heap::GCTypeTimer(GarbageCollector collector) {
1116   if (IsYoungGenerationCollector(collector)) {
1117     return isolate_->counters()->gc_scavenger();
1118   } else {
1119     if (!incremental_marking()->IsStopped()) {
1120       if (ShouldReduceMemory()) {
1121         return isolate_->counters()->gc_finalize_reduce_memory();
1122       } else {
1123         return isolate_->counters()->gc_finalize();
1124       }
1125     } else {
1126       return isolate_->counters()->gc_compactor();
1127     }
1128   }
1129 }
1130 
CollectAllGarbage(int flags,GarbageCollectionReason gc_reason,const v8::GCCallbackFlags gc_callback_flags)1131 void Heap::CollectAllGarbage(int flags, GarbageCollectionReason gc_reason,
1132                              const v8::GCCallbackFlags gc_callback_flags) {
1133   // Since we are ignoring the return value, the exact choice of space does
1134   // not matter, so long as we do not specify NEW_SPACE, which would not
1135   // cause a full GC.
1136   set_current_gc_flags(flags);
1137   CollectGarbage(OLD_SPACE, gc_reason, gc_callback_flags);
1138   set_current_gc_flags(kNoGCFlags);
1139 }
1140 
1141 namespace {
1142 
CompareWords(int size,HeapObject * a,HeapObject * b)1143 intptr_t CompareWords(int size, HeapObject* a, HeapObject* b) {
1144   int words = size / kPointerSize;
1145   DCHECK_EQ(a->Size(), size);
1146   DCHECK_EQ(b->Size(), size);
1147   intptr_t* slot_a = reinterpret_cast<intptr_t*>(a->address());
1148   intptr_t* slot_b = reinterpret_cast<intptr_t*>(b->address());
1149   for (int i = 0; i < words; i++) {
1150     if (*slot_a != *slot_b) {
1151       return *slot_a - *slot_b;
1152     }
1153     slot_a++;
1154     slot_b++;
1155   }
1156   return 0;
1157 }
1158 
ReportDuplicates(int size,std::vector<HeapObject * > & objects)1159 void ReportDuplicates(int size, std::vector<HeapObject*>& objects) {
1160   if (objects.size() == 0) return;
1161 
1162   sort(objects.begin(), objects.end(), [size](HeapObject* a, HeapObject* b) {
1163     intptr_t c = CompareWords(size, a, b);
1164     if (c != 0) return c < 0;
1165     return a < b;
1166   });
1167 
1168   std::vector<std::pair<int, HeapObject*>> duplicates;
1169   HeapObject* current = objects[0];
1170   int count = 1;
1171   for (size_t i = 1; i < objects.size(); i++) {
1172     if (CompareWords(size, current, objects[i]) == 0) {
1173       count++;
1174     } else {
1175       if (count > 1) {
1176         duplicates.push_back(std::make_pair(count - 1, current));
1177       }
1178       count = 1;
1179       current = objects[i];
1180     }
1181   }
1182   if (count > 1) {
1183     duplicates.push_back(std::make_pair(count - 1, current));
1184   }
1185 
1186   int threshold = FLAG_trace_duplicate_threshold_kb * KB;
1187 
1188   sort(duplicates.begin(), duplicates.end());
1189   for (auto it = duplicates.rbegin(); it != duplicates.rend(); ++it) {
1190     int duplicate_bytes = it->first * size;
1191     if (duplicate_bytes < threshold) break;
1192     PrintF("%d duplicates of size %d each (%dKB)\n", it->first, size,
1193            duplicate_bytes / KB);
1194     PrintF("Sample object: ");
1195     it->second->Print();
1196     PrintF("============================\n");
1197   }
1198 }
1199 }  // anonymous namespace
1200 
CollectAllAvailableGarbage(GarbageCollectionReason gc_reason)1201 void Heap::CollectAllAvailableGarbage(GarbageCollectionReason gc_reason) {
1202   // Since we are ignoring the return value, the exact choice of space does
1203   // not matter, so long as we do not specify NEW_SPACE, which would not
1204   // cause a full GC.
1205   // Major GC would invoke weak handle callbacks on weakly reachable
1206   // handles, but won't collect weakly reachable objects until next
1207   // major GC.  Therefore if we collect aggressively and weak handle callback
1208   // has been invoked, we rerun major GC to release objects which become
1209   // garbage.
1210   // Note: as weak callbacks can execute arbitrary code, we cannot
1211   // hope that eventually there will be no weak callbacks invocations.
1212   // Therefore stop recollecting after several attempts.
1213   if (gc_reason == GarbageCollectionReason::kLastResort) {
1214     InvokeNearHeapLimitCallback();
1215   }
1216   RuntimeCallTimerScope runtime_timer(
1217       isolate(), RuntimeCallCounterId::kGC_Custom_AllAvailableGarbage);
1218 
1219   // The optimizing compiler may be unnecessarily holding on to memory.
1220   isolate()->AbortConcurrentOptimization(BlockingBehavior::kDontBlock);
1221   isolate()->ClearSerializerData();
1222   set_current_gc_flags(kMakeHeapIterableMask | kReduceMemoryFootprintMask);
1223   isolate_->compilation_cache()->Clear();
1224   const int kMaxNumberOfAttempts = 7;
1225   const int kMinNumberOfAttempts = 2;
1226   for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) {
1227     if (!CollectGarbage(OLD_SPACE, gc_reason,
1228                         v8::kGCCallbackFlagCollectAllAvailableGarbage) &&
1229         attempt + 1 >= kMinNumberOfAttempts) {
1230       break;
1231     }
1232   }
1233 
1234   set_current_gc_flags(kNoGCFlags);
1235   new_space_->Shrink();
1236   UncommitFromSpace();
1237   memory_allocator()->unmapper()->EnsureUnmappingCompleted();
1238 
1239   if (FLAG_trace_duplicate_threshold_kb) {
1240     std::map<int, std::vector<HeapObject*>> objects_by_size;
1241     PagedSpaces spaces(this);
1242     for (PagedSpace* space = spaces.next(); space != nullptr;
1243          space = spaces.next()) {
1244       HeapObjectIterator it(space);
1245       for (HeapObject* obj = it.Next(); obj != nullptr; obj = it.Next()) {
1246         objects_by_size[obj->Size()].push_back(obj);
1247       }
1248     }
1249     {
1250       LargeObjectIterator it(lo_space());
1251       for (HeapObject* obj = it.Next(); obj != nullptr; obj = it.Next()) {
1252         objects_by_size[obj->Size()].push_back(obj);
1253       }
1254     }
1255     for (auto it = objects_by_size.rbegin(); it != objects_by_size.rend();
1256          ++it) {
1257       ReportDuplicates(it->first, it->second);
1258     }
1259   }
1260 }
1261 
ReportExternalMemoryPressure()1262 void Heap::ReportExternalMemoryPressure() {
1263   const GCCallbackFlags kGCCallbackFlagsForExternalMemory =
1264       static_cast<GCCallbackFlags>(
1265           kGCCallbackFlagSynchronousPhantomCallbackProcessing |
1266           kGCCallbackFlagCollectAllExternalMemory);
1267   if (external_memory_ >
1268       (external_memory_at_last_mark_compact_ + external_memory_hard_limit())) {
1269     CollectAllGarbage(
1270         kReduceMemoryFootprintMask | kFinalizeIncrementalMarkingMask,
1271         GarbageCollectionReason::kExternalMemoryPressure,
1272         static_cast<GCCallbackFlags>(kGCCallbackFlagCollectAllAvailableGarbage |
1273                                      kGCCallbackFlagsForExternalMemory));
1274     return;
1275   }
1276   if (incremental_marking()->IsStopped()) {
1277     if (incremental_marking()->CanBeActivated()) {
1278       StartIncrementalMarking(GCFlagsForIncrementalMarking(),
1279                               GarbageCollectionReason::kExternalMemoryPressure,
1280                               kGCCallbackFlagsForExternalMemory);
1281     } else {
1282       CollectAllGarbage(i::Heap::kNoGCFlags,
1283                         GarbageCollectionReason::kExternalMemoryPressure,
1284                         kGCCallbackFlagsForExternalMemory);
1285     }
1286   } else {
1287     // Incremental marking is turned on an has already been started.
1288     const double kMinStepSize = 5;
1289     const double kMaxStepSize = 10;
1290     const double ms_step =
1291         Min(kMaxStepSize,
1292             Max(kMinStepSize, static_cast<double>(external_memory_) /
1293                                   external_memory_limit_ * kMinStepSize));
1294     const double deadline = MonotonicallyIncreasingTimeInMs() + ms_step;
1295     // Extend the gc callback flags with external memory flags.
1296     current_gc_callback_flags_ = static_cast<GCCallbackFlags>(
1297         current_gc_callback_flags_ | kGCCallbackFlagsForExternalMemory);
1298     incremental_marking()->AdvanceIncrementalMarking(
1299         deadline, IncrementalMarking::GC_VIA_STACK_GUARD, StepOrigin::kV8);
1300   }
1301 }
1302 
EnsureFillerObjectAtTop()1303 void Heap::EnsureFillerObjectAtTop() {
1304   // There may be an allocation memento behind objects in new space. Upon
1305   // evacuation of a non-full new space (or if we are on the last page) there
1306   // may be uninitialized memory behind top. We fill the remainder of the page
1307   // with a filler.
1308   Address to_top = new_space_->top();
1309   Page* page = Page::FromAddress(to_top - kPointerSize);
1310   if (page->Contains(to_top)) {
1311     int remaining_in_page = static_cast<int>(page->area_end() - to_top);
1312     CreateFillerObjectAt(to_top, remaining_in_page, ClearRecordedSlots::kNo);
1313   }
1314 }
1315 
CollectGarbage(AllocationSpace space,GarbageCollectionReason gc_reason,const v8::GCCallbackFlags gc_callback_flags)1316 bool Heap::CollectGarbage(AllocationSpace space,
1317                           GarbageCollectionReason gc_reason,
1318                           const v8::GCCallbackFlags gc_callback_flags) {
1319   const char* collector_reason = nullptr;
1320   GarbageCollector collector = SelectGarbageCollector(space, &collector_reason);
1321 
1322   if (!CanExpandOldGeneration(new_space()->Capacity())) {
1323     InvokeNearHeapLimitCallback();
1324   }
1325 
1326   // Ensure that all pending phantom callbacks are invoked.
1327   isolate()->global_handles()->InvokeSecondPassPhantomCallbacks();
1328 
1329   // The VM is in the GC state until exiting this function.
1330   VMState<GC> state(isolate());
1331 
1332 #ifdef V8_ENABLE_ALLOCATION_TIMEOUT
1333   // Reset the allocation timeout, but make sure to allow at least a few
1334   // allocations after a collection. The reason for this is that we have a lot
1335   // of allocation sequences and we assume that a garbage collection will allow
1336   // the subsequent allocation attempts to go through.
1337   if (FLAG_random_gc_interval > 0 || FLAG_gc_interval >= 0) {
1338     allocation_timeout_ = Max(6, NextAllocationTimeout(allocation_timeout_));
1339   }
1340 #endif
1341 
1342   EnsureFillerObjectAtTop();
1343 
1344   if (IsYoungGenerationCollector(collector) &&
1345       !incremental_marking()->IsStopped()) {
1346     if (FLAG_trace_incremental_marking) {
1347       isolate()->PrintWithTimestamp(
1348           "[IncrementalMarking] Scavenge during marking.\n");
1349     }
1350   }
1351 
1352   bool next_gc_likely_to_collect_more = false;
1353   size_t committed_memory_before = 0;
1354 
1355   if (collector == MARK_COMPACTOR) {
1356     committed_memory_before = CommittedOldGenerationMemory();
1357   }
1358 
1359   {
1360     tracer()->Start(collector, gc_reason, collector_reason);
1361     DCHECK(AllowHeapAllocation::IsAllowed());
1362     DisallowHeapAllocation no_allocation_during_gc;
1363     GarbageCollectionPrologue();
1364 
1365     {
1366       HistogramTimer* gc_type_timer = GCTypeTimer(collector);
1367       HistogramTimerScope histogram_timer_scope(gc_type_timer);
1368       TRACE_EVENT0("v8", gc_type_timer->name());
1369 
1370       HistogramTimer* gc_type_priority_timer = GCTypePriorityTimer(collector);
1371       OptionalHistogramTimerScopeMode mode =
1372           isolate_->IsMemorySavingsModeActive()
1373               ? OptionalHistogramTimerScopeMode::DONT_TAKE_TIME
1374               : OptionalHistogramTimerScopeMode::TAKE_TIME;
1375       OptionalHistogramTimerScope histogram_timer_priority_scope(
1376           gc_type_priority_timer, mode);
1377 
1378       next_gc_likely_to_collect_more =
1379           PerformGarbageCollection(collector, gc_callback_flags);
1380       if (collector == MARK_COMPACTOR) {
1381         tracer()->RecordMarkCompactHistograms(gc_type_timer);
1382       }
1383     }
1384 
1385     GarbageCollectionEpilogue();
1386     if (collector == MARK_COMPACTOR && FLAG_track_detached_contexts) {
1387       isolate()->CheckDetachedContextsAfterGC();
1388     }
1389 
1390     if (collector == MARK_COMPACTOR) {
1391       size_t committed_memory_after = CommittedOldGenerationMemory();
1392       size_t used_memory_after = OldGenerationSizeOfObjects();
1393       MemoryReducer::Event event;
1394       event.type = MemoryReducer::kMarkCompact;
1395       event.time_ms = MonotonicallyIncreasingTimeInMs();
1396       // Trigger one more GC if
1397       // - this GC decreased committed memory,
1398       // - there is high fragmentation,
1399       // - there are live detached contexts.
1400       event.next_gc_likely_to_collect_more =
1401           (committed_memory_before > committed_memory_after + MB) ||
1402           HasHighFragmentation(used_memory_after, committed_memory_after) ||
1403           (detached_contexts()->length() > 0);
1404       event.committed_memory = committed_memory_after;
1405       if (deserialization_complete_) {
1406         memory_reducer_->NotifyMarkCompact(event);
1407       }
1408     }
1409 
1410     tracer()->Stop(collector);
1411   }
1412 
1413   if (collector == MARK_COMPACTOR &&
1414       (gc_callback_flags & (kGCCallbackFlagForced |
1415                             kGCCallbackFlagCollectAllAvailableGarbage)) != 0) {
1416     isolate()->CountUsage(v8::Isolate::kForcedGC);
1417   }
1418 
1419   // Start incremental marking for the next cycle. The heap snapshot
1420   // generator needs incremental marking to stay off after it aborted.
1421   // We do this only for scavenger to avoid a loop where mark-compact
1422   // causes another mark-compact.
1423   if (IsYoungGenerationCollector(collector) &&
1424       !ShouldAbortIncrementalMarking()) {
1425     StartIncrementalMarkingIfAllocationLimitIsReached(
1426         GCFlagsForIncrementalMarking(),
1427         kGCCallbackScheduleIdleGarbageCollection);
1428   }
1429 
1430   return next_gc_likely_to_collect_more;
1431 }
1432 
1433 
NotifyContextDisposed(bool dependant_context)1434 int Heap::NotifyContextDisposed(bool dependant_context) {
1435   if (!dependant_context) {
1436     tracer()->ResetSurvivalEvents();
1437     old_generation_size_configured_ = false;
1438     MemoryReducer::Event event;
1439     event.type = MemoryReducer::kPossibleGarbage;
1440     event.time_ms = MonotonicallyIncreasingTimeInMs();
1441     memory_reducer_->NotifyPossibleGarbage(event);
1442   }
1443   isolate()->AbortConcurrentOptimization(BlockingBehavior::kDontBlock);
1444 
1445   number_of_disposed_maps_ = retained_maps()->length();
1446   tracer()->AddContextDisposalTime(MonotonicallyIncreasingTimeInMs());
1447   return ++contexts_disposed_;
1448 }
1449 
StartIncrementalMarking(int gc_flags,GarbageCollectionReason gc_reason,GCCallbackFlags gc_callback_flags)1450 void Heap::StartIncrementalMarking(int gc_flags,
1451                                    GarbageCollectionReason gc_reason,
1452                                    GCCallbackFlags gc_callback_flags) {
1453   DCHECK(incremental_marking()->IsStopped());
1454   set_current_gc_flags(gc_flags);
1455   current_gc_callback_flags_ = gc_callback_flags;
1456   incremental_marking()->Start(gc_reason);
1457 }
1458 
StartIncrementalMarkingIfAllocationLimitIsReached(int gc_flags,const GCCallbackFlags gc_callback_flags)1459 void Heap::StartIncrementalMarkingIfAllocationLimitIsReached(
1460     int gc_flags, const GCCallbackFlags gc_callback_flags) {
1461   if (incremental_marking()->IsStopped()) {
1462     IncrementalMarkingLimit reached_limit = IncrementalMarkingLimitReached();
1463     if (reached_limit == IncrementalMarkingLimit::kSoftLimit) {
1464       incremental_marking()->incremental_marking_job()->ScheduleTask(this);
1465     } else if (reached_limit == IncrementalMarkingLimit::kHardLimit) {
1466       StartIncrementalMarking(gc_flags,
1467                               GarbageCollectionReason::kAllocationLimit,
1468                               gc_callback_flags);
1469     }
1470   }
1471 }
1472 
StartIdleIncrementalMarking(GarbageCollectionReason gc_reason,const GCCallbackFlags gc_callback_flags)1473 void Heap::StartIdleIncrementalMarking(
1474     GarbageCollectionReason gc_reason,
1475     const GCCallbackFlags gc_callback_flags) {
1476   gc_idle_time_handler_->ResetNoProgressCounter();
1477   StartIncrementalMarking(kReduceMemoryFootprintMask, gc_reason,
1478                           gc_callback_flags);
1479 }
1480 
MoveElements(FixedArray * array,int dst_index,int src_index,int len,WriteBarrierMode mode)1481 void Heap::MoveElements(FixedArray* array, int dst_index, int src_index,
1482                         int len, WriteBarrierMode mode) {
1483   if (len == 0) return;
1484 
1485   DCHECK(array->map() != ReadOnlyRoots(this).fixed_cow_array_map());
1486   Object** dst = array->data_start() + dst_index;
1487   Object** src = array->data_start() + src_index;
1488   if (FLAG_concurrent_marking && incremental_marking()->IsMarking()) {
1489     if (dst < src) {
1490       for (int i = 0; i < len; i++) {
1491         base::AsAtomicPointer::Relaxed_Store(
1492             dst + i, base::AsAtomicPointer::Relaxed_Load(src + i));
1493       }
1494     } else {
1495       for (int i = len - 1; i >= 0; i--) {
1496         base::AsAtomicPointer::Relaxed_Store(
1497             dst + i, base::AsAtomicPointer::Relaxed_Load(src + i));
1498       }
1499     }
1500   } else {
1501     MemMove(dst, src, len * kPointerSize);
1502   }
1503   if (mode == SKIP_WRITE_BARRIER) return;
1504   FIXED_ARRAY_ELEMENTS_WRITE_BARRIER(this, array, dst_index, len);
1505 }
1506 
1507 
1508 #ifdef VERIFY_HEAP
1509 // Helper class for verifying the string table.
1510 class StringTableVerifier : public ObjectVisitor {
1511  public:
StringTableVerifier(Isolate * isolate)1512   explicit StringTableVerifier(Isolate* isolate) : isolate_(isolate) {}
1513 
VisitPointers(HeapObject * host,Object ** start,Object ** end)1514   void VisitPointers(HeapObject* host, Object** start, Object** end) override {
1515     // Visit all HeapObject pointers in [start, end).
1516     for (Object** p = start; p < end; p++) {
1517       DCHECK(!HasWeakHeapObjectTag(*p));
1518       if ((*p)->IsHeapObject()) {
1519         HeapObject* object = HeapObject::cast(*p);
1520         // Check that the string is actually internalized.
1521         CHECK(object->IsTheHole(isolate_) || object->IsUndefined(isolate_) ||
1522               object->IsInternalizedString());
1523       }
1524     }
1525   }
VisitPointers(HeapObject * host,MaybeObject ** start,MaybeObject ** end)1526   void VisitPointers(HeapObject* host, MaybeObject** start,
1527                      MaybeObject** end) override {
1528     UNREACHABLE();
1529   }
1530 
1531  private:
1532   Isolate* isolate_;
1533 };
1534 
VerifyStringTable(Isolate * isolate)1535 static void VerifyStringTable(Isolate* isolate) {
1536   StringTableVerifier verifier(isolate);
1537   isolate->heap()->string_table()->IterateElements(&verifier);
1538 }
1539 #endif  // VERIFY_HEAP
1540 
ReserveSpace(Reservation * reservations,std::vector<Address> * maps)1541 bool Heap::ReserveSpace(Reservation* reservations, std::vector<Address>* maps) {
1542   bool gc_performed = true;
1543   int counter = 0;
1544   static const int kThreshold = 20;
1545   while (gc_performed && counter++ < kThreshold) {
1546     gc_performed = false;
1547     for (int space = FIRST_SPACE;
1548          space < SerializerDeserializer::kNumberOfSpaces; space++) {
1549       Reservation* reservation = &reservations[space];
1550       DCHECK_LE(1, reservation->size());
1551       if (reservation->at(0).size == 0) {
1552         DCHECK_EQ(1, reservation->size());
1553         continue;
1554       }
1555       bool perform_gc = false;
1556       if (space == MAP_SPACE) {
1557         // We allocate each map individually to avoid fragmentation.
1558         maps->clear();
1559         DCHECK_LE(reservation->size(), 2);
1560         int reserved_size = 0;
1561         for (const Chunk& c : *reservation) reserved_size += c.size;
1562         DCHECK_EQ(0, reserved_size % Map::kSize);
1563         int num_maps = reserved_size / Map::kSize;
1564         for (int i = 0; i < num_maps; i++) {
1565           // The deserializer will update the skip list.
1566           AllocationResult allocation = map_space()->AllocateRawUnaligned(
1567               Map::kSize, PagedSpace::IGNORE_SKIP_LIST);
1568           HeapObject* free_space = nullptr;
1569           if (allocation.To(&free_space)) {
1570             // Mark with a free list node, in case we have a GC before
1571             // deserializing.
1572             Address free_space_address = free_space->address();
1573             CreateFillerObjectAt(free_space_address, Map::kSize,
1574                                  ClearRecordedSlots::kNo);
1575             maps->push_back(free_space_address);
1576           } else {
1577             perform_gc = true;
1578             break;
1579           }
1580         }
1581       } else if (space == LO_SPACE) {
1582         // Just check that we can allocate during deserialization.
1583         DCHECK_LE(reservation->size(), 2);
1584         int reserved_size = 0;
1585         for (const Chunk& c : *reservation) reserved_size += c.size;
1586         perform_gc = !CanExpandOldGeneration(reserved_size);
1587       } else {
1588         for (auto& chunk : *reservation) {
1589           AllocationResult allocation;
1590           int size = chunk.size;
1591           DCHECK_LE(static_cast<size_t>(size),
1592                     MemoryAllocator::PageAreaSize(
1593                         static_cast<AllocationSpace>(space)));
1594           if (space == NEW_SPACE) {
1595             allocation = new_space()->AllocateRawUnaligned(size);
1596           } else {
1597             // The deserializer will update the skip list.
1598             allocation = paged_space(space)->AllocateRawUnaligned(
1599                 size, PagedSpace::IGNORE_SKIP_LIST);
1600           }
1601           HeapObject* free_space = nullptr;
1602           if (allocation.To(&free_space)) {
1603             // Mark with a free list node, in case we have a GC before
1604             // deserializing.
1605             Address free_space_address = free_space->address();
1606             CreateFillerObjectAt(free_space_address, size,
1607                                  ClearRecordedSlots::kNo);
1608             DCHECK_GT(SerializerDeserializer::kNumberOfPreallocatedSpaces,
1609                       space);
1610             chunk.start = free_space_address;
1611             chunk.end = free_space_address + size;
1612           } else {
1613             perform_gc = true;
1614             break;
1615           }
1616         }
1617       }
1618       if (perform_gc) {
1619         // We cannot perfom a GC with an uninitialized isolate. This check
1620         // fails for example if the max old space size is chosen unwisely,
1621         // so that we cannot allocate space to deserialize the initial heap.
1622         if (!deserialization_complete_) {
1623           V8::FatalProcessOutOfMemory(
1624               isolate(), "insufficient memory to create an Isolate");
1625         }
1626         if (space == NEW_SPACE) {
1627           CollectGarbage(NEW_SPACE, GarbageCollectionReason::kDeserializer);
1628         } else {
1629           if (counter > 1) {
1630             CollectAllGarbage(
1631                 kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask,
1632                 GarbageCollectionReason::kDeserializer);
1633           } else {
1634             CollectAllGarbage(kAbortIncrementalMarkingMask,
1635                               GarbageCollectionReason::kDeserializer);
1636           }
1637         }
1638         gc_performed = true;
1639         break;  // Abort for-loop over spaces and retry.
1640       }
1641     }
1642   }
1643 
1644   return !gc_performed;
1645 }
1646 
1647 
EnsureFromSpaceIsCommitted()1648 void Heap::EnsureFromSpaceIsCommitted() {
1649   if (new_space_->CommitFromSpaceIfNeeded()) return;
1650 
1651   // Committing memory to from space failed.
1652   // Memory is exhausted and we will die.
1653   FatalProcessOutOfMemory("Committing semi space failed.");
1654 }
1655 
1656 
UpdateSurvivalStatistics(int start_new_space_size)1657 void Heap::UpdateSurvivalStatistics(int start_new_space_size) {
1658   if (start_new_space_size == 0) return;
1659 
1660   promotion_ratio_ = (static_cast<double>(promoted_objects_size_) /
1661                       static_cast<double>(start_new_space_size) * 100);
1662 
1663   if (previous_semi_space_copied_object_size_ > 0) {
1664     promotion_rate_ =
1665         (static_cast<double>(promoted_objects_size_) /
1666          static_cast<double>(previous_semi_space_copied_object_size_) * 100);
1667   } else {
1668     promotion_rate_ = 0;
1669   }
1670 
1671   semi_space_copied_rate_ =
1672       (static_cast<double>(semi_space_copied_object_size_) /
1673        static_cast<double>(start_new_space_size) * 100);
1674 
1675   double survival_rate = promotion_ratio_ + semi_space_copied_rate_;
1676   tracer()->AddSurvivalRatio(survival_rate);
1677 }
1678 
PerformGarbageCollection(GarbageCollector collector,const v8::GCCallbackFlags gc_callback_flags)1679 bool Heap::PerformGarbageCollection(
1680     GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) {
1681   int freed_global_handles = 0;
1682 
1683   if (!IsYoungGenerationCollector(collector)) {
1684     PROFILE(isolate_, CodeMovingGCEvent());
1685   }
1686 
1687 #ifdef VERIFY_HEAP
1688   if (FLAG_verify_heap) {
1689     VerifyStringTable(this->isolate());
1690   }
1691 #endif
1692 
1693   GCType gc_type =
1694       collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge;
1695 
1696   {
1697     GCCallbacksScope scope(this);
1698     if (scope.CheckReenter()) {
1699       AllowHeapAllocation allow_allocation;
1700       TRACE_GC(tracer(), GCTracer::Scope::HEAP_EXTERNAL_PROLOGUE);
1701       VMState<EXTERNAL> state(isolate_);
1702       HandleScope handle_scope(isolate_);
1703       CallGCPrologueCallbacks(gc_type, kNoGCCallbackFlags);
1704     }
1705   }
1706 
1707   EnsureFromSpaceIsCommitted();
1708 
1709   size_t start_new_space_size = Heap::new_space()->Size();
1710 
1711   {
1712     Heap::SkipStoreBufferScope skip_store_buffer_scope(store_buffer_);
1713 
1714     switch (collector) {
1715       case MARK_COMPACTOR:
1716         UpdateOldGenerationAllocationCounter();
1717         // Perform mark-sweep with optional compaction.
1718         MarkCompact();
1719         old_generation_size_configured_ = true;
1720         // This should be updated before PostGarbageCollectionProcessing, which
1721         // can cause another GC. Take into account the objects promoted during
1722         // GC.
1723         old_generation_allocation_counter_at_last_gc_ +=
1724             static_cast<size_t>(promoted_objects_size_);
1725         old_generation_size_at_last_gc_ = OldGenerationSizeOfObjects();
1726         break;
1727       case MINOR_MARK_COMPACTOR:
1728         MinorMarkCompact();
1729         break;
1730       case SCAVENGER:
1731         if ((fast_promotion_mode_ &&
1732              CanExpandOldGeneration(new_space()->Size()))) {
1733           tracer()->NotifyYoungGenerationHandling(
1734               YoungGenerationHandling::kFastPromotionDuringScavenge);
1735           EvacuateYoungGeneration();
1736         } else {
1737           tracer()->NotifyYoungGenerationHandling(
1738               YoungGenerationHandling::kRegularScavenge);
1739 
1740           Scavenge();
1741         }
1742         break;
1743     }
1744 
1745     ProcessPretenuringFeedback();
1746   }
1747 
1748   UpdateSurvivalStatistics(static_cast<int>(start_new_space_size));
1749   ConfigureInitialOldGenerationSize();
1750 
1751   if (collector != MARK_COMPACTOR) {
1752     // Objects that died in the new space might have been accounted
1753     // as bytes marked ahead of schedule by the incremental marker.
1754     incremental_marking()->UpdateMarkedBytesAfterScavenge(
1755         start_new_space_size - SurvivedNewSpaceObjectSize());
1756   }
1757 
1758   if (!fast_promotion_mode_ || collector == MARK_COMPACTOR) {
1759     ComputeFastPromotionMode();
1760   }
1761 
1762   isolate_->counters()->objs_since_last_young()->Set(0);
1763 
1764   gc_post_processing_depth_++;
1765   {
1766     AllowHeapAllocation allow_allocation;
1767     TRACE_GC(tracer(), GCTracer::Scope::HEAP_EXTERNAL_WEAK_GLOBAL_HANDLES);
1768     freed_global_handles =
1769         isolate_->global_handles()->PostGarbageCollectionProcessing(
1770             collector, gc_callback_flags);
1771   }
1772   gc_post_processing_depth_--;
1773 
1774   isolate_->eternal_handles()->PostGarbageCollectionProcessing();
1775 
1776   // Update relocatables.
1777   Relocatable::PostGarbageCollectionProcessing(isolate_);
1778 
1779   double gc_speed = tracer()->CombinedMarkCompactSpeedInBytesPerMillisecond();
1780   double mutator_speed =
1781       tracer()->CurrentOldGenerationAllocationThroughputInBytesPerMillisecond();
1782   size_t old_gen_size = OldGenerationSizeOfObjects();
1783   if (collector == MARK_COMPACTOR) {
1784     // Register the amount of external allocated memory.
1785     external_memory_at_last_mark_compact_ = external_memory_;
1786     external_memory_limit_ = external_memory_ + kExternalAllocationSoftLimit;
1787 
1788     size_t new_limit = heap_controller()->CalculateAllocationLimit(
1789         old_gen_size, max_old_generation_size_, gc_speed, mutator_speed,
1790         new_space()->Capacity(), CurrentHeapGrowingMode());
1791     old_generation_allocation_limit_ = new_limit;
1792 
1793     CheckIneffectiveMarkCompact(
1794         old_gen_size, tracer()->AverageMarkCompactMutatorUtilization());
1795   } else if (HasLowYoungGenerationAllocationRate() &&
1796              old_generation_size_configured_) {
1797     size_t new_limit = heap_controller()->CalculateAllocationLimit(
1798         old_gen_size, max_old_generation_size_, gc_speed, mutator_speed,
1799         new_space()->Capacity(), CurrentHeapGrowingMode());
1800     if (new_limit < old_generation_allocation_limit_) {
1801       old_generation_allocation_limit_ = new_limit;
1802     }
1803   }
1804 
1805   {
1806     GCCallbacksScope scope(this);
1807     if (scope.CheckReenter()) {
1808       AllowHeapAllocation allow_allocation;
1809       TRACE_GC(tracer(), GCTracer::Scope::HEAP_EXTERNAL_EPILOGUE);
1810       VMState<EXTERNAL> state(isolate_);
1811       HandleScope handle_scope(isolate_);
1812       CallGCEpilogueCallbacks(gc_type, gc_callback_flags);
1813     }
1814   }
1815 
1816 #ifdef VERIFY_HEAP
1817   if (FLAG_verify_heap) {
1818     VerifyStringTable(this->isolate());
1819   }
1820 #endif
1821 
1822   return freed_global_handles > 0;
1823 }
1824 
1825 
CallGCPrologueCallbacks(GCType gc_type,GCCallbackFlags flags)1826 void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) {
1827   RuntimeCallTimerScope runtime_timer(
1828       isolate(), RuntimeCallCounterId::kGCPrologueCallback);
1829   for (const GCCallbackTuple& info : gc_prologue_callbacks_) {
1830     if (gc_type & info.gc_type) {
1831       v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate());
1832       info.callback(isolate, gc_type, flags, info.data);
1833     }
1834   }
1835 }
1836 
CallGCEpilogueCallbacks(GCType gc_type,GCCallbackFlags flags)1837 void Heap::CallGCEpilogueCallbacks(GCType gc_type, GCCallbackFlags flags) {
1838   RuntimeCallTimerScope runtime_timer(
1839       isolate(), RuntimeCallCounterId::kGCEpilogueCallback);
1840   for (const GCCallbackTuple& info : gc_epilogue_callbacks_) {
1841     if (gc_type & info.gc_type) {
1842       v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate());
1843       info.callback(isolate, gc_type, flags, info.data);
1844     }
1845   }
1846 }
1847 
1848 
MarkCompact()1849 void Heap::MarkCompact() {
1850   PauseAllocationObserversScope pause_observers(this);
1851 
1852   SetGCState(MARK_COMPACT);
1853 
1854   LOG(isolate_, ResourceEvent("markcompact", "begin"));
1855 
1856   uint64_t size_of_objects_before_gc = SizeOfObjects();
1857 
1858   CodeSpaceMemoryModificationScope code_modifcation(this);
1859 
1860   mark_compact_collector()->Prepare();
1861 
1862   ms_count_++;
1863 
1864   MarkCompactPrologue();
1865 
1866   mark_compact_collector()->CollectGarbage();
1867 
1868   LOG(isolate_, ResourceEvent("markcompact", "end"));
1869 
1870   MarkCompactEpilogue();
1871 
1872   if (FLAG_allocation_site_pretenuring) {
1873     EvaluateOldSpaceLocalPretenuring(size_of_objects_before_gc);
1874   }
1875 }
1876 
MinorMarkCompact()1877 void Heap::MinorMarkCompact() {
1878 #ifdef ENABLE_MINOR_MC
1879   DCHECK(FLAG_minor_mc);
1880 
1881   PauseAllocationObserversScope pause_observers(this);
1882   SetGCState(MINOR_MARK_COMPACT);
1883   LOG(isolate_, ResourceEvent("MinorMarkCompact", "begin"));
1884 
1885   TRACE_GC(tracer(), GCTracer::Scope::MINOR_MC);
1886   AlwaysAllocateScope always_allocate(isolate());
1887   IncrementalMarking::PauseBlackAllocationScope pause_black_allocation(
1888       incremental_marking());
1889   ConcurrentMarking::PauseScope pause_scope(concurrent_marking());
1890 
1891   minor_mark_compact_collector()->CollectGarbage();
1892 
1893   LOG(isolate_, ResourceEvent("MinorMarkCompact", "end"));
1894   SetGCState(NOT_IN_GC);
1895 #else
1896   UNREACHABLE();
1897 #endif  // ENABLE_MINOR_MC
1898 }
1899 
MarkCompactEpilogue()1900 void Heap::MarkCompactEpilogue() {
1901   TRACE_GC(tracer(), GCTracer::Scope::MC_EPILOGUE);
1902   SetGCState(NOT_IN_GC);
1903 
1904   isolate_->counters()->objs_since_last_full()->Set(0);
1905 
1906   incremental_marking()->Epilogue();
1907 
1908   DCHECK(incremental_marking()->IsStopped());
1909 }
1910 
1911 
MarkCompactPrologue()1912 void Heap::MarkCompactPrologue() {
1913   TRACE_GC(tracer(), GCTracer::Scope::MC_PROLOGUE);
1914   isolate_->context_slot_cache()->Clear();
1915   isolate_->descriptor_lookup_cache()->Clear();
1916   RegExpResultsCache::Clear(string_split_cache());
1917   RegExpResultsCache::Clear(regexp_multiple_cache());
1918 
1919   isolate_->compilation_cache()->MarkCompactPrologue();
1920 
1921   FlushNumberStringCache();
1922 }
1923 
1924 
CheckNewSpaceExpansionCriteria()1925 void Heap::CheckNewSpaceExpansionCriteria() {
1926   if (FLAG_experimental_new_space_growth_heuristic) {
1927     if (new_space_->TotalCapacity() < new_space_->MaximumCapacity() &&
1928         survived_last_scavenge_ * 100 / new_space_->TotalCapacity() >= 10) {
1929       // Grow the size of new space if there is room to grow, and more than 10%
1930       // have survived the last scavenge.
1931       new_space_->Grow();
1932       survived_since_last_expansion_ = 0;
1933     }
1934   } else if (new_space_->TotalCapacity() < new_space_->MaximumCapacity() &&
1935              survived_since_last_expansion_ > new_space_->TotalCapacity()) {
1936     // Grow the size of new space if there is room to grow, and enough data
1937     // has survived scavenge since the last expansion.
1938     new_space_->Grow();
1939     survived_since_last_expansion_ = 0;
1940   }
1941 }
1942 
IsUnscavengedHeapObject(Heap * heap,Object ** p)1943 static bool IsUnscavengedHeapObject(Heap* heap, Object** p) {
1944   return Heap::InFromSpace(*p) &&
1945          !HeapObject::cast(*p)->map_word().IsForwardingAddress();
1946 }
1947 
1948 class ScavengeWeakObjectRetainer : public WeakObjectRetainer {
1949  public:
RetainAs(Object * object)1950   virtual Object* RetainAs(Object* object) {
1951     if (!Heap::InFromSpace(object)) {
1952       return object;
1953     }
1954 
1955     MapWord map_word = HeapObject::cast(object)->map_word();
1956     if (map_word.IsForwardingAddress()) {
1957       return map_word.ToForwardingAddress();
1958     }
1959     return nullptr;
1960   }
1961 };
1962 
EvacuateYoungGeneration()1963 void Heap::EvacuateYoungGeneration() {
1964   TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_FAST_PROMOTE);
1965   base::LockGuard<base::Mutex> guard(relocation_mutex());
1966   ConcurrentMarking::PauseScope pause_scope(concurrent_marking());
1967   if (!FLAG_concurrent_marking) {
1968     DCHECK(fast_promotion_mode_);
1969     DCHECK(CanExpandOldGeneration(new_space()->Size()));
1970   }
1971 
1972   mark_compact_collector()->sweeper()->EnsureIterabilityCompleted();
1973 
1974   SetGCState(SCAVENGE);
1975   LOG(isolate_, ResourceEvent("scavenge", "begin"));
1976 
1977   // Move pages from new->old generation.
1978   PageRange range(new_space()->first_allocatable_address(), new_space()->top());
1979   for (auto it = range.begin(); it != range.end();) {
1980     Page* p = (*++it)->prev_page();
1981     new_space()->from_space().RemovePage(p);
1982     Page::ConvertNewToOld(p);
1983     if (incremental_marking()->IsMarking())
1984       mark_compact_collector()->RecordLiveSlotsOnPage(p);
1985   }
1986 
1987   // Reset new space.
1988   if (!new_space()->Rebalance()) {
1989     FatalProcessOutOfMemory("NewSpace::Rebalance");
1990   }
1991   new_space()->ResetLinearAllocationArea();
1992   new_space()->set_age_mark(new_space()->top());
1993 
1994   // Fix up special trackers.
1995   external_string_table_.PromoteAllNewSpaceStrings();
1996   // GlobalHandles are updated in PostGarbageCollectonProcessing
1997 
1998   IncrementYoungSurvivorsCounter(new_space()->Size());
1999   IncrementPromotedObjectsSize(new_space()->Size());
2000   IncrementSemiSpaceCopiedObjectSize(0);
2001 
2002   LOG(isolate_, ResourceEvent("scavenge", "end"));
2003   SetGCState(NOT_IN_GC);
2004 }
2005 
IsLogging(Isolate * isolate)2006 static bool IsLogging(Isolate* isolate) {
2007   return FLAG_verify_predictable || isolate->logger()->is_logging() ||
2008          isolate->is_profiling() ||
2009          (isolate->heap_profiler() != nullptr &&
2010           isolate->heap_profiler()->is_tracking_object_moves()) ||
2011          isolate->heap()->has_heap_object_allocation_tracker();
2012 }
2013 
2014 class PageScavengingItem final : public ItemParallelJob::Item {
2015  public:
PageScavengingItem(MemoryChunk * chunk)2016   explicit PageScavengingItem(MemoryChunk* chunk) : chunk_(chunk) {}
~PageScavengingItem()2017   virtual ~PageScavengingItem() {}
2018 
Process(Scavenger * scavenger)2019   void Process(Scavenger* scavenger) { scavenger->ScavengePage(chunk_); }
2020 
2021  private:
2022   MemoryChunk* const chunk_;
2023 };
2024 
2025 class ScavengingTask final : public ItemParallelJob::Task {
2026  public:
ScavengingTask(Heap * heap,Scavenger * scavenger,OneshotBarrier * barrier)2027   ScavengingTask(Heap* heap, Scavenger* scavenger, OneshotBarrier* barrier)
2028       : ItemParallelJob::Task(heap->isolate()),
2029         heap_(heap),
2030         scavenger_(scavenger),
2031         barrier_(barrier) {}
2032 
RunInParallel()2033   void RunInParallel() final {
2034     TRACE_BACKGROUND_GC(
2035         heap_->tracer(),
2036         GCTracer::BackgroundScope::SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL);
2037     double scavenging_time = 0.0;
2038     {
2039       barrier_->Start();
2040       TimedScope scope(&scavenging_time);
2041       PageScavengingItem* item = nullptr;
2042       while ((item = GetItem<PageScavengingItem>()) != nullptr) {
2043         item->Process(scavenger_);
2044         item->MarkFinished();
2045       }
2046       do {
2047         scavenger_->Process(barrier_);
2048       } while (!barrier_->Wait());
2049       scavenger_->Process();
2050     }
2051     if (FLAG_trace_parallel_scavenge) {
2052       PrintIsolate(heap_->isolate(),
2053                    "scavenge[%p]: time=%.2f copied=%zu promoted=%zu\n",
2054                    static_cast<void*>(this), scavenging_time,
2055                    scavenger_->bytes_copied(), scavenger_->bytes_promoted());
2056     }
2057   };
2058 
2059  private:
2060   Heap* const heap_;
2061   Scavenger* const scavenger_;
2062   OneshotBarrier* const barrier_;
2063 };
2064 
NumberOfScavengeTasks()2065 int Heap::NumberOfScavengeTasks() {
2066   if (!FLAG_parallel_scavenge) return 1;
2067   const int num_scavenge_tasks =
2068       static_cast<int>(new_space()->TotalCapacity()) / MB;
2069   static int num_cores = V8::GetCurrentPlatform()->NumberOfWorkerThreads() + 1;
2070   int tasks =
2071       Max(1, Min(Min(num_scavenge_tasks, kMaxScavengerTasks), num_cores));
2072   if (!CanExpandOldGeneration(static_cast<size_t>(tasks * Page::kPageSize))) {
2073     // Optimize for memory usage near the heap limit.
2074     tasks = 1;
2075   }
2076   return tasks;
2077 }
2078 
Scavenge()2079 void Heap::Scavenge() {
2080   TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE);
2081   base::LockGuard<base::Mutex> guard(relocation_mutex());
2082   ConcurrentMarking::PauseScope pause_scope(concurrent_marking());
2083   // There are soft limits in the allocation code, designed to trigger a mark
2084   // sweep collection by failing allocations. There is no sense in trying to
2085   // trigger one during scavenge: scavenges allocation should always succeed.
2086   AlwaysAllocateScope scope(isolate());
2087 
2088   // Bump-pointer allocations done during scavenge are not real allocations.
2089   // Pause the inline allocation steps.
2090   PauseAllocationObserversScope pause_observers(this);
2091 
2092   IncrementalMarking::PauseBlackAllocationScope pause_black_allocation(
2093       incremental_marking());
2094 
2095 
2096   mark_compact_collector()->sweeper()->EnsureIterabilityCompleted();
2097 
2098   SetGCState(SCAVENGE);
2099 
2100   // Implements Cheney's copying algorithm
2101   LOG(isolate_, ResourceEvent("scavenge", "begin"));
2102 
2103   // Flip the semispaces.  After flipping, to space is empty, from space has
2104   // live objects.
2105   new_space_->Flip();
2106   new_space_->ResetLinearAllocationArea();
2107 
2108   ItemParallelJob job(isolate()->cancelable_task_manager(),
2109                       &parallel_scavenge_semaphore_);
2110   const int kMainThreadId = 0;
2111   Scavenger* scavengers[kMaxScavengerTasks];
2112   const bool is_logging = IsLogging(isolate());
2113   const int num_scavenge_tasks = NumberOfScavengeTasks();
2114   OneshotBarrier barrier;
2115   Scavenger::CopiedList copied_list(num_scavenge_tasks);
2116   Scavenger::PromotionList promotion_list(num_scavenge_tasks);
2117   for (int i = 0; i < num_scavenge_tasks; i++) {
2118     scavengers[i] =
2119         new Scavenger(this, is_logging, &copied_list, &promotion_list, i);
2120     job.AddTask(new ScavengingTask(this, scavengers[i], &barrier));
2121   }
2122 
2123   {
2124     Sweeper* sweeper = mark_compact_collector()->sweeper();
2125     // Pause the concurrent sweeper.
2126     Sweeper::PauseOrCompleteScope pause_scope(sweeper);
2127     // Filter out pages from the sweeper that need to be processed for old to
2128     // new slots by the Scavenger. After processing, the Scavenger adds back
2129     // pages that are still unsweeped. This way the Scavenger has exclusive
2130     // access to the slots of a page and can completely avoid any locks on
2131     // the page itself.
2132     Sweeper::FilterSweepingPagesScope filter_scope(sweeper, pause_scope);
2133     filter_scope.FilterOldSpaceSweepingPages(
2134         [](Page* page) { return !page->ContainsSlots<OLD_TO_NEW>(); });
2135     RememberedSet<OLD_TO_NEW>::IterateMemoryChunks(
2136         this, [&job](MemoryChunk* chunk) {
2137           job.AddItem(new PageScavengingItem(chunk));
2138         });
2139 
2140     RootScavengeVisitor root_scavenge_visitor(scavengers[kMainThreadId]);
2141 
2142     {
2143       // Identify weak unmodified handles. Requires an unmodified graph.
2144       TRACE_GC(
2145           tracer(),
2146           GCTracer::Scope::SCAVENGER_SCAVENGE_WEAK_GLOBAL_HANDLES_IDENTIFY);
2147       isolate()->global_handles()->IdentifyWeakUnmodifiedObjects(
2148           &JSObject::IsUnmodifiedApiObject);
2149     }
2150     {
2151       // Copy roots.
2152       TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE_ROOTS);
2153       IterateRoots(&root_scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
2154     }
2155     {
2156       // Parallel phase scavenging all copied and promoted objects.
2157       TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE_PARALLEL);
2158       job.Run(isolate()->async_counters());
2159       DCHECK(copied_list.IsEmpty());
2160       DCHECK(promotion_list.IsEmpty());
2161     }
2162     {
2163       // Scavenge weak global handles.
2164       TRACE_GC(tracer(),
2165                GCTracer::Scope::SCAVENGER_SCAVENGE_WEAK_GLOBAL_HANDLES_PROCESS);
2166       isolate()->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending(
2167           &IsUnscavengedHeapObject);
2168       isolate()
2169           ->global_handles()
2170           ->IterateNewSpaceWeakUnmodifiedRootsForFinalizers(
2171               &root_scavenge_visitor);
2172       scavengers[kMainThreadId]->Process();
2173 
2174       DCHECK(copied_list.IsEmpty());
2175       DCHECK(promotion_list.IsEmpty());
2176       isolate()
2177           ->global_handles()
2178           ->IterateNewSpaceWeakUnmodifiedRootsForPhantomHandles(
2179               &root_scavenge_visitor, &IsUnscavengedHeapObject);
2180     }
2181 
2182     for (int i = 0; i < num_scavenge_tasks; i++) {
2183       scavengers[i]->Finalize();
2184       delete scavengers[i];
2185     }
2186   }
2187 
2188   {
2189     // Update references into new space
2190     TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_SCAVENGE_UPDATE_REFS);
2191     UpdateNewSpaceReferencesInExternalStringTable(
2192         &UpdateNewSpaceReferenceInExternalStringTableEntry);
2193 
2194     incremental_marking()->UpdateMarkingWorklistAfterScavenge();
2195   }
2196 
2197   if (FLAG_concurrent_marking) {
2198     // Ensure that concurrent marker does not track pages that are
2199     // going to be unmapped.
2200     for (Page* p : PageRange(new_space()->from_space().first_page(), nullptr)) {
2201       concurrent_marking()->ClearLiveness(p);
2202     }
2203   }
2204 
2205   ScavengeWeakObjectRetainer weak_object_retainer;
2206   ProcessYoungWeakReferences(&weak_object_retainer);
2207 
2208   // Set age mark.
2209   new_space_->set_age_mark(new_space_->top());
2210 
2211   {
2212     TRACE_GC(tracer(), GCTracer::Scope::SCAVENGER_PROCESS_ARRAY_BUFFERS);
2213     ArrayBufferTracker::PrepareToFreeDeadInNewSpace(this);
2214   }
2215   array_buffer_collector()->FreeAllocationsOnBackgroundThread();
2216 
2217   RememberedSet<OLD_TO_NEW>::IterateMemoryChunks(this, [](MemoryChunk* chunk) {
2218     if (chunk->SweepingDone()) {
2219       RememberedSet<OLD_TO_NEW>::FreeEmptyBuckets(chunk);
2220     } else {
2221       RememberedSet<OLD_TO_NEW>::PreFreeEmptyBuckets(chunk);
2222     }
2223   });
2224 
2225   // Update how much has survived scavenge.
2226   IncrementYoungSurvivorsCounter(SurvivedNewSpaceObjectSize());
2227 
2228   // Scavenger may find new wrappers by iterating objects promoted onto a black
2229   // page.
2230   local_embedder_heap_tracer()->RegisterWrappersWithRemoteTracer();
2231 
2232   LOG(isolate_, ResourceEvent("scavenge", "end"));
2233 
2234   SetGCState(NOT_IN_GC);
2235 }
2236 
ComputeFastPromotionMode()2237 void Heap::ComputeFastPromotionMode() {
2238   const size_t survived_in_new_space =
2239       survived_last_scavenge_ * 100 / new_space_->Capacity();
2240   fast_promotion_mode_ =
2241       !FLAG_optimize_for_size && FLAG_fast_promotion_new_space &&
2242       !ShouldReduceMemory() && new_space_->IsAtMaximumCapacity() &&
2243       survived_in_new_space >= kMinPromotedPercentForFastPromotionMode;
2244   if (FLAG_trace_gc_verbose && !FLAG_trace_gc_ignore_scavenger) {
2245     PrintIsolate(
2246         isolate(), "Fast promotion mode: %s survival rate: %" PRIuS "%%\n",
2247         fast_promotion_mode_ ? "true" : "false", survived_in_new_space);
2248   }
2249 }
2250 
UnprotectAndRegisterMemoryChunk(MemoryChunk * chunk)2251 void Heap::UnprotectAndRegisterMemoryChunk(MemoryChunk* chunk) {
2252   if (unprotected_memory_chunks_registry_enabled_) {
2253     base::LockGuard<base::Mutex> guard(&unprotected_memory_chunks_mutex_);
2254     if (unprotected_memory_chunks_.insert(chunk).second) {
2255       chunk->SetReadAndWritable();
2256     }
2257   }
2258 }
2259 
UnprotectAndRegisterMemoryChunk(HeapObject * object)2260 void Heap::UnprotectAndRegisterMemoryChunk(HeapObject* object) {
2261   UnprotectAndRegisterMemoryChunk(MemoryChunk::FromAddress(object->address()));
2262 }
2263 
UnregisterUnprotectedMemoryChunk(MemoryChunk * chunk)2264 void Heap::UnregisterUnprotectedMemoryChunk(MemoryChunk* chunk) {
2265   unprotected_memory_chunks_.erase(chunk);
2266 }
2267 
ProtectUnprotectedMemoryChunks()2268 void Heap::ProtectUnprotectedMemoryChunks() {
2269   DCHECK(unprotected_memory_chunks_registry_enabled_);
2270   for (auto chunk = unprotected_memory_chunks_.begin();
2271        chunk != unprotected_memory_chunks_.end(); chunk++) {
2272     CHECK(memory_allocator()->IsMemoryChunkExecutable(*chunk));
2273     (*chunk)->SetReadAndExecutable();
2274   }
2275   unprotected_memory_chunks_.clear();
2276 }
2277 
Contains(HeapObject * obj)2278 bool Heap::ExternalStringTable::Contains(HeapObject* obj) {
2279   for (size_t i = 0; i < new_space_strings_.size(); ++i) {
2280     if (new_space_strings_[i] == obj) return true;
2281   }
2282   for (size_t i = 0; i < old_space_strings_.size(); ++i) {
2283     if (old_space_strings_[i] == obj) return true;
2284   }
2285   return false;
2286 }
2287 
ProcessMovedExternalString(Page * old_page,Page * new_page,ExternalString * string)2288 void Heap::ProcessMovedExternalString(Page* old_page, Page* new_page,
2289                                       ExternalString* string) {
2290   size_t size = string->ExternalPayloadSize();
2291   new_page->IncrementExternalBackingStoreBytes(
2292       ExternalBackingStoreType::kExternalString, size);
2293   old_page->DecrementExternalBackingStoreBytes(
2294       ExternalBackingStoreType::kExternalString, size);
2295 }
2296 
UpdateNewSpaceReferenceInExternalStringTableEntry(Heap * heap,Object ** p)2297 String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
2298                                                                 Object** p) {
2299   MapWord first_word = HeapObject::cast(*p)->map_word();
2300 
2301   if (!first_word.IsForwardingAddress()) {
2302     // Unreachable external string can be finalized.
2303     String* string = String::cast(*p);
2304     if (!string->IsExternalString()) {
2305       // Original external string has been internalized.
2306       DCHECK(string->IsThinString());
2307       return nullptr;
2308     }
2309     heap->FinalizeExternalString(string);
2310     return nullptr;
2311   }
2312 
2313   // String is still reachable.
2314   String* new_string = String::cast(first_word.ToForwardingAddress());
2315   String* original_string = reinterpret_cast<String*>(*p);
2316   // The length of the original string is used to disambiguate the scenario
2317   // of a ThingString being forwarded to an ExternalString (which already exists
2318   // in the OLD space), and an ExternalString being forwarded to its promoted
2319   // copy. See Scavenger::EvacuateThinString.
2320   if (new_string->IsThinString() || original_string->length() == 0) {
2321     // Filtering Thin strings out of the external string table.
2322     return nullptr;
2323   } else if (new_string->IsExternalString()) {
2324     heap->ProcessMovedExternalString(
2325         Page::FromAddress(reinterpret_cast<Address>(*p)),
2326         Page::FromHeapObject(new_string), ExternalString::cast(new_string));
2327     return new_string;
2328   }
2329 
2330   // Internalization can replace external strings with non-external strings.
2331   return new_string->IsExternalString() ? new_string : nullptr;
2332 }
2333 
VerifyNewSpace()2334 void Heap::ExternalStringTable::VerifyNewSpace() {
2335 #ifdef DEBUG
2336   std::set<String*> visited_map;
2337   std::map<MemoryChunk*, size_t> size_map;
2338   ExternalBackingStoreType type = ExternalBackingStoreType::kExternalString;
2339   for (size_t i = 0; i < new_space_strings_.size(); ++i) {
2340     String* obj = String::cast(new_space_strings_[i]);
2341     MemoryChunk* mc = MemoryChunk::FromHeapObject(obj);
2342     DCHECK(mc->InNewSpace());
2343     DCHECK(heap_->InNewSpace(obj));
2344     DCHECK(!obj->IsTheHole(heap_->isolate()));
2345     DCHECK(obj->IsExternalString());
2346     // Note: we can have repeated elements in the table.
2347     DCHECK_EQ(0, visited_map.count(obj));
2348     visited_map.insert(obj);
2349     size_map[mc] += ExternalString::cast(obj)->ExternalPayloadSize();
2350   }
2351   for (std::map<MemoryChunk*, size_t>::iterator it = size_map.begin();
2352        it != size_map.end(); it++)
2353     DCHECK_EQ(it->first->ExternalBackingStoreBytes(type), it->second);
2354 #endif
2355 }
2356 
Verify()2357 void Heap::ExternalStringTable::Verify() {
2358 #ifdef DEBUG
2359   std::set<String*> visited_map;
2360   std::map<MemoryChunk*, size_t> size_map;
2361   ExternalBackingStoreType type = ExternalBackingStoreType::kExternalString;
2362   VerifyNewSpace();
2363   for (size_t i = 0; i < old_space_strings_.size(); ++i) {
2364     String* obj = String::cast(old_space_strings_[i]);
2365     MemoryChunk* mc = MemoryChunk::FromHeapObject(obj);
2366     DCHECK(!mc->InNewSpace());
2367     DCHECK(!heap_->InNewSpace(obj));
2368     DCHECK(!obj->IsTheHole(heap_->isolate()));
2369     DCHECK(obj->IsExternalString());
2370     // Note: we can have repeated elements in the table.
2371     DCHECK_EQ(0, visited_map.count(obj));
2372     visited_map.insert(obj);
2373     size_map[mc] += ExternalString::cast(obj)->ExternalPayloadSize();
2374   }
2375   for (std::map<MemoryChunk*, size_t>::iterator it = size_map.begin();
2376        it != size_map.end(); it++)
2377     DCHECK_EQ(it->first->ExternalBackingStoreBytes(type), it->second);
2378 #endif
2379 }
2380 
UpdateNewSpaceReferences(Heap::ExternalStringTableUpdaterCallback updater_func)2381 void Heap::ExternalStringTable::UpdateNewSpaceReferences(
2382     Heap::ExternalStringTableUpdaterCallback updater_func) {
2383   if (new_space_strings_.empty()) return;
2384 
2385   Object** start = new_space_strings_.data();
2386   Object** end = start + new_space_strings_.size();
2387   Object** last = start;
2388 
2389   for (Object** p = start; p < end; ++p) {
2390     String* target = updater_func(heap_, p);
2391 
2392     if (target == nullptr) continue;
2393 
2394     DCHECK(target->IsExternalString());
2395 
2396     if (InNewSpace(target)) {
2397       // String is still in new space. Update the table entry.
2398       *last = target;
2399       ++last;
2400     } else {
2401       // String got promoted. Move it to the old string list.
2402       old_space_strings_.push_back(target);
2403     }
2404   }
2405 
2406   DCHECK_LE(last, end);
2407   new_space_strings_.resize(static_cast<size_t>(last - start));
2408 #ifdef VERIFY_HEAP
2409   if (FLAG_verify_heap) {
2410     VerifyNewSpace();
2411   }
2412 #endif
2413 }
2414 
PromoteAllNewSpaceStrings()2415 void Heap::ExternalStringTable::PromoteAllNewSpaceStrings() {
2416   old_space_strings_.reserve(old_space_strings_.size() +
2417                              new_space_strings_.size());
2418   std::move(std::begin(new_space_strings_), std::end(new_space_strings_),
2419             std::back_inserter(old_space_strings_));
2420   new_space_strings_.clear();
2421 }
2422 
IterateNewSpaceStrings(RootVisitor * v)2423 void Heap::ExternalStringTable::IterateNewSpaceStrings(RootVisitor* v) {
2424   if (!new_space_strings_.empty()) {
2425     v->VisitRootPointers(Root::kExternalStringsTable, nullptr,
2426                          new_space_strings_.data(),
2427                          new_space_strings_.data() + new_space_strings_.size());
2428   }
2429 }
2430 
IterateAll(RootVisitor * v)2431 void Heap::ExternalStringTable::IterateAll(RootVisitor* v) {
2432   IterateNewSpaceStrings(v);
2433   if (!old_space_strings_.empty()) {
2434     v->VisitRootPointers(Root::kExternalStringsTable, nullptr,
2435                          old_space_strings_.data(),
2436                          old_space_strings_.data() + old_space_strings_.size());
2437   }
2438 }
2439 
UpdateNewSpaceReferencesInExternalStringTable(ExternalStringTableUpdaterCallback updater_func)2440 void Heap::UpdateNewSpaceReferencesInExternalStringTable(
2441     ExternalStringTableUpdaterCallback updater_func) {
2442   external_string_table_.UpdateNewSpaceReferences(updater_func);
2443 }
2444 
UpdateReferences(Heap::ExternalStringTableUpdaterCallback updater_func)2445 void Heap::ExternalStringTable::UpdateReferences(
2446     Heap::ExternalStringTableUpdaterCallback updater_func) {
2447   if (old_space_strings_.size() > 0) {
2448     Object** start = old_space_strings_.data();
2449     Object** end = start + old_space_strings_.size();
2450     for (Object** p = start; p < end; ++p) *p = updater_func(heap_, p);
2451   }
2452 
2453   UpdateNewSpaceReferences(updater_func);
2454 }
2455 
UpdateReferencesInExternalStringTable(ExternalStringTableUpdaterCallback updater_func)2456 void Heap::UpdateReferencesInExternalStringTable(
2457     ExternalStringTableUpdaterCallback updater_func) {
2458   external_string_table_.UpdateReferences(updater_func);
2459 }
2460 
2461 
ProcessAllWeakReferences(WeakObjectRetainer * retainer)2462 void Heap::ProcessAllWeakReferences(WeakObjectRetainer* retainer) {
2463   ProcessNativeContexts(retainer);
2464   ProcessAllocationSites(retainer);
2465 }
2466 
2467 
ProcessYoungWeakReferences(WeakObjectRetainer * retainer)2468 void Heap::ProcessYoungWeakReferences(WeakObjectRetainer* retainer) {
2469   ProcessNativeContexts(retainer);
2470 }
2471 
2472 
ProcessNativeContexts(WeakObjectRetainer * retainer)2473 void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer) {
2474   Object* head = VisitWeakList<Context>(this, native_contexts_list(), retainer);
2475   // Update the head of the list of contexts.
2476   set_native_contexts_list(head);
2477 }
2478 
2479 
ProcessAllocationSites(WeakObjectRetainer * retainer)2480 void Heap::ProcessAllocationSites(WeakObjectRetainer* retainer) {
2481   Object* allocation_site_obj =
2482       VisitWeakList<AllocationSite>(this, allocation_sites_list(), retainer);
2483   set_allocation_sites_list(allocation_site_obj);
2484 }
2485 
ProcessWeakListRoots(WeakObjectRetainer * retainer)2486 void Heap::ProcessWeakListRoots(WeakObjectRetainer* retainer) {
2487   set_native_contexts_list(retainer->RetainAs(native_contexts_list()));
2488   set_allocation_sites_list(retainer->RetainAs(allocation_sites_list()));
2489 }
2490 
ForeachAllocationSite(Object * list,std::function<void (AllocationSite *)> visitor)2491 void Heap::ForeachAllocationSite(Object* list,
2492                                  std::function<void(AllocationSite*)> visitor) {
2493   DisallowHeapAllocation disallow_heap_allocation;
2494   Object* current = list;
2495   while (current->IsAllocationSite()) {
2496     AllocationSite* site = AllocationSite::cast(current);
2497     visitor(site);
2498     Object* current_nested = site->nested_site();
2499     while (current_nested->IsAllocationSite()) {
2500       AllocationSite* nested_site = AllocationSite::cast(current_nested);
2501       visitor(nested_site);
2502       current_nested = nested_site->nested_site();
2503     }
2504     current = site->weak_next();
2505   }
2506 }
2507 
ResetAllAllocationSitesDependentCode(PretenureFlag flag)2508 void Heap::ResetAllAllocationSitesDependentCode(PretenureFlag flag) {
2509   DisallowHeapAllocation no_allocation_scope;
2510   bool marked = false;
2511 
2512   ForeachAllocationSite(allocation_sites_list(),
2513                         [&marked, flag, this](AllocationSite* site) {
2514                           if (site->GetPretenureMode() == flag) {
2515                             site->ResetPretenureDecision();
2516                             site->set_deopt_dependent_code(true);
2517                             marked = true;
2518                             RemoveAllocationSitePretenuringFeedback(site);
2519                             return;
2520                           }
2521                         });
2522   if (marked) isolate_->stack_guard()->RequestDeoptMarkedAllocationSites();
2523 }
2524 
2525 
EvaluateOldSpaceLocalPretenuring(uint64_t size_of_objects_before_gc)2526 void Heap::EvaluateOldSpaceLocalPretenuring(
2527     uint64_t size_of_objects_before_gc) {
2528   uint64_t size_of_objects_after_gc = SizeOfObjects();
2529   double old_generation_survival_rate =
2530       (static_cast<double>(size_of_objects_after_gc) * 100) /
2531       static_cast<double>(size_of_objects_before_gc);
2532 
2533   if (old_generation_survival_rate < kOldSurvivalRateLowThreshold) {
2534     // Too many objects died in the old generation, pretenuring of wrong
2535     // allocation sites may be the cause for that. We have to deopt all
2536     // dependent code registered in the allocation sites to re-evaluate
2537     // our pretenuring decisions.
2538     ResetAllAllocationSitesDependentCode(TENURED);
2539     if (FLAG_trace_pretenuring) {
2540       PrintF(
2541           "Deopt all allocation sites dependent code due to low survival "
2542           "rate in the old generation %f\n",
2543           old_generation_survival_rate);
2544     }
2545   }
2546 }
2547 
2548 
VisitExternalResources(v8::ExternalResourceVisitor * visitor)2549 void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
2550   DisallowHeapAllocation no_allocation;
2551   // All external strings are listed in the external string table.
2552 
2553   class ExternalStringTableVisitorAdapter : public RootVisitor {
2554    public:
2555     explicit ExternalStringTableVisitorAdapter(
2556         Isolate* isolate, v8::ExternalResourceVisitor* visitor)
2557         : isolate_(isolate), visitor_(visitor) {}
2558     virtual void VisitRootPointers(Root root, const char* description,
2559                                    Object** start, Object** end) {
2560       for (Object** p = start; p < end; p++) {
2561         DCHECK((*p)->IsExternalString());
2562         visitor_->VisitExternalString(
2563             Utils::ToLocal(Handle<String>(String::cast(*p), isolate_)));
2564       }
2565     }
2566 
2567    private:
2568     Isolate* isolate_;
2569     v8::ExternalResourceVisitor* visitor_;
2570   } external_string_table_visitor(isolate(), visitor);
2571 
2572   external_string_table_.IterateAll(&external_string_table_visitor);
2573 }
2574 
2575 STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) ==
2576               0);  // NOLINT
2577 STATIC_ASSERT((FixedTypedArrayBase::kDataOffset & kDoubleAlignmentMask) ==
2578               0);  // NOLINT
2579 #ifdef V8_HOST_ARCH_32_BIT
2580 STATIC_ASSERT((HeapNumber::kValueOffset & kDoubleAlignmentMask) !=
2581               0);  // NOLINT
2582 #endif
2583 
2584 
GetMaximumFillToAlign(AllocationAlignment alignment)2585 int Heap::GetMaximumFillToAlign(AllocationAlignment alignment) {
2586   switch (alignment) {
2587     case kWordAligned:
2588       return 0;
2589     case kDoubleAligned:
2590     case kDoubleUnaligned:
2591       return kDoubleSize - kPointerSize;
2592     default:
2593       UNREACHABLE();
2594   }
2595   return 0;
2596 }
2597 
2598 
GetFillToAlign(Address address,AllocationAlignment alignment)2599 int Heap::GetFillToAlign(Address address, AllocationAlignment alignment) {
2600   intptr_t offset = OffsetFrom(address);
2601   if (alignment == kDoubleAligned && (offset & kDoubleAlignmentMask) != 0)
2602     return kPointerSize;
2603   if (alignment == kDoubleUnaligned && (offset & kDoubleAlignmentMask) == 0)
2604     return kDoubleSize - kPointerSize;  // No fill if double is always aligned.
2605   return 0;
2606 }
2607 
2608 
PrecedeWithFiller(HeapObject * object,int filler_size)2609 HeapObject* Heap::PrecedeWithFiller(HeapObject* object, int filler_size) {
2610   CreateFillerObjectAt(object->address(), filler_size, ClearRecordedSlots::kNo);
2611   return HeapObject::FromAddress(object->address() + filler_size);
2612 }
2613 
2614 
AlignWithFiller(HeapObject * object,int object_size,int allocation_size,AllocationAlignment alignment)2615 HeapObject* Heap::AlignWithFiller(HeapObject* object, int object_size,
2616                                   int allocation_size,
2617                                   AllocationAlignment alignment) {
2618   int filler_size = allocation_size - object_size;
2619   DCHECK_LT(0, filler_size);
2620   int pre_filler = GetFillToAlign(object->address(), alignment);
2621   if (pre_filler) {
2622     object = PrecedeWithFiller(object, pre_filler);
2623     filler_size -= pre_filler;
2624   }
2625   if (filler_size)
2626     CreateFillerObjectAt(object->address() + object_size, filler_size,
2627                          ClearRecordedSlots::kNo);
2628   return object;
2629 }
2630 
RegisterNewArrayBuffer(JSArrayBuffer * buffer)2631 void Heap::RegisterNewArrayBuffer(JSArrayBuffer* buffer) {
2632   ArrayBufferTracker::RegisterNew(this, buffer);
2633 }
2634 
2635 
UnregisterArrayBuffer(JSArrayBuffer * buffer)2636 void Heap::UnregisterArrayBuffer(JSArrayBuffer* buffer) {
2637   ArrayBufferTracker::Unregister(this, buffer);
2638 }
2639 
ConfigureInitialOldGenerationSize()2640 void Heap::ConfigureInitialOldGenerationSize() {
2641   if (!old_generation_size_configured_ && tracer()->SurvivalEventsRecorded()) {
2642     old_generation_allocation_limit_ =
2643         Max(heap_controller()->MinimumAllocationLimitGrowingStep(
2644                 CurrentHeapGrowingMode()),
2645             static_cast<size_t>(
2646                 static_cast<double>(old_generation_allocation_limit_) *
2647                 (tracer()->AverageSurvivalRatio() / 100)));
2648   }
2649 }
2650 
CreateJSEntryStub()2651 void Heap::CreateJSEntryStub() {
2652   JSEntryStub stub(isolate(), StackFrame::ENTRY);
2653   set_js_entry_code(*stub.GetCode());
2654 }
2655 
2656 
CreateJSConstructEntryStub()2657 void Heap::CreateJSConstructEntryStub() {
2658   JSEntryStub stub(isolate(), StackFrame::CONSTRUCT_ENTRY);
2659   set_js_construct_entry_code(*stub.GetCode());
2660 }
2661 
CreateJSRunMicrotasksEntryStub()2662 void Heap::CreateJSRunMicrotasksEntryStub() {
2663   JSEntryStub stub(isolate(), JSEntryStub::SpecialTarget::kRunMicrotasks);
2664   set_js_run_microtasks_entry_code(*stub.GetCode());
2665 }
2666 
CreateFixedStubs()2667 void Heap::CreateFixedStubs() {
2668   // Here we create roots for fixed stubs. They are needed at GC
2669   // for cooking and uncooking (check out frames.cc).
2670   // The eliminates the need for doing dictionary lookup in the
2671   // stub cache for these stubs.
2672   HandleScope scope(isolate());
2673   // Canonicalize handles, so that we can share constant pool entries pointing
2674   // to code targets without dereferencing their handles.
2675   CanonicalHandleScope canonical(isolate());
2676 
2677   // Create stubs that should be there, so we don't unexpectedly have to
2678   // create them if we need them during the creation of another stub.
2679   // Stub creation mixes raw pointers and handles in an unsafe manner so
2680   // we cannot create stubs while we are creating stubs.
2681   CodeStub::GenerateStubsAheadOfTime(isolate());
2682 
2683   // gcc-4.4 has problem generating correct code of following snippet:
2684   // {  JSEntryStub stub;
2685   //    js_entry_code_ = *stub.GetCode();
2686   // }
2687   // {  JSConstructEntryStub stub;
2688   //    js_construct_entry_code_ = *stub.GetCode();
2689   // }
2690   // To workaround the problem, make separate functions without inlining.
2691   Heap::CreateJSEntryStub();
2692   Heap::CreateJSConstructEntryStub();
2693   Heap::CreateJSRunMicrotasksEntryStub();
2694 }
2695 
RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index)2696 bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
2697   switch (root_index) {
2698     case kNumberStringCacheRootIndex:
2699     case kCodeStubsRootIndex:
2700     case kScriptListRootIndex:
2701     case kMaterializedObjectsRootIndex:
2702     case kMicrotaskQueueRootIndex:
2703     case kDetachedContextsRootIndex:
2704     case kRetainedMapsRootIndex:
2705     case kRetainingPathTargetsRootIndex:
2706     case kFeedbackVectorsForProfilingToolsRootIndex:
2707     case kNoScriptSharedFunctionInfosRootIndex:
2708     case kSerializedObjectsRootIndex:
2709     case kSerializedGlobalProxySizesRootIndex:
2710     case kPublicSymbolTableRootIndex:
2711     case kApiSymbolTableRootIndex:
2712     case kApiPrivateSymbolTableRootIndex:
2713     case kMessageListenersRootIndex:
2714     case kDeserializeLazyHandlerRootIndex:
2715     case kDeserializeLazyHandlerWideRootIndex:
2716     case kDeserializeLazyHandlerExtraWideRootIndex:
2717 // Smi values
2718 #define SMI_ENTRY(type, name, Name) case k##Name##RootIndex:
2719       SMI_ROOT_LIST(SMI_ENTRY)
2720 #undef SMI_ENTRY
2721     // String table
2722     case kStringTableRootIndex:
2723       return true;
2724 
2725     default:
2726       return false;
2727   }
2728 }
2729 
RootCanBeTreatedAsConstant(RootListIndex root_index)2730 bool Heap::RootCanBeTreatedAsConstant(RootListIndex root_index) {
2731   bool can_be = !RootCanBeWrittenAfterInitialization(root_index) &&
2732                 !InNewSpace(root(root_index));
2733   DCHECK_IMPLIES(can_be, IsImmovable(HeapObject::cast(root(root_index))));
2734   return can_be;
2735 }
2736 
2737 
FlushNumberStringCache()2738 void Heap::FlushNumberStringCache() {
2739   // Flush the number to string cache.
2740   int len = number_string_cache()->length();
2741   for (int i = 0; i < len; i++) {
2742     number_string_cache()->set_undefined(i);
2743   }
2744 }
2745 
2746 namespace {
2747 
RootIndexForFixedTypedArray(ExternalArrayType array_type)2748 Heap::RootListIndex RootIndexForFixedTypedArray(ExternalArrayType array_type) {
2749   switch (array_type) {
2750 #define ARRAY_TYPE_TO_ROOT_INDEX(Type, type, TYPE, ctype) \
2751   case kExternal##Type##Array:                            \
2752     return Heap::kFixed##Type##ArrayMapRootIndex;
2753 
2754     TYPED_ARRAYS(ARRAY_TYPE_TO_ROOT_INDEX)
2755 #undef ARRAY_TYPE_TO_ROOT_INDEX
2756   }
2757   UNREACHABLE();
2758 }
2759 
RootIndexForFixedTypedArray(ElementsKind elements_kind)2760 Heap::RootListIndex RootIndexForFixedTypedArray(ElementsKind elements_kind) {
2761   switch (elements_kind) {
2762 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
2763   case TYPE##_ELEMENTS:                           \
2764     return Heap::kFixed##Type##ArrayMapRootIndex;
2765     TYPED_ARRAYS(TYPED_ARRAY_CASE)
2766     default:
2767       UNREACHABLE();
2768 #undef TYPED_ARRAY_CASE
2769   }
2770 }
2771 
RootIndexForEmptyFixedTypedArray(ElementsKind elements_kind)2772 Heap::RootListIndex RootIndexForEmptyFixedTypedArray(
2773     ElementsKind elements_kind) {
2774   switch (elements_kind) {
2775 #define ELEMENT_KIND_TO_ROOT_INDEX(Type, type, TYPE, ctype) \
2776   case TYPE##_ELEMENTS:                                     \
2777     return Heap::kEmptyFixed##Type##ArrayRootIndex;
2778 
2779     TYPED_ARRAYS(ELEMENT_KIND_TO_ROOT_INDEX)
2780 #undef ELEMENT_KIND_TO_ROOT_INDEX
2781     default:
2782       UNREACHABLE();
2783   }
2784 }
2785 
2786 }  // namespace
2787 
MapForFixedTypedArray(ExternalArrayType array_type)2788 Map* Heap::MapForFixedTypedArray(ExternalArrayType array_type) {
2789   return Map::cast(roots_[RootIndexForFixedTypedArray(array_type)]);
2790 }
2791 
MapForFixedTypedArray(ElementsKind elements_kind)2792 Map* Heap::MapForFixedTypedArray(ElementsKind elements_kind) {
2793   return Map::cast(roots_[RootIndexForFixedTypedArray(elements_kind)]);
2794 }
2795 
EmptyFixedTypedArrayForMap(const Map * map)2796 FixedTypedArrayBase* Heap::EmptyFixedTypedArrayForMap(const Map* map) {
2797   return FixedTypedArrayBase::cast(
2798       roots_[RootIndexForEmptyFixedTypedArray(map->elements_kind())]);
2799 }
2800 
CreateFillerObjectAt(Address addr,int size,ClearRecordedSlots clear_slots_mode,ClearFreedMemoryMode clear_memory_mode)2801 HeapObject* Heap::CreateFillerObjectAt(Address addr, int size,
2802                                        ClearRecordedSlots clear_slots_mode,
2803                                        ClearFreedMemoryMode clear_memory_mode) {
2804   if (size == 0) return nullptr;
2805   HeapObject* filler = HeapObject::FromAddress(addr);
2806   if (size == kPointerSize) {
2807     filler->set_map_after_allocation(
2808         reinterpret_cast<Map*>(root(kOnePointerFillerMapRootIndex)),
2809         SKIP_WRITE_BARRIER);
2810   } else if (size == 2 * kPointerSize) {
2811     filler->set_map_after_allocation(
2812         reinterpret_cast<Map*>(root(kTwoPointerFillerMapRootIndex)),
2813         SKIP_WRITE_BARRIER);
2814     if (clear_memory_mode == ClearFreedMemoryMode::kClearFreedMemory) {
2815       Memory<Address>(addr + kPointerSize) =
2816           static_cast<Address>(kClearedFreeMemoryValue);
2817     }
2818   } else {
2819     DCHECK_GT(size, 2 * kPointerSize);
2820     filler->set_map_after_allocation(
2821         reinterpret_cast<Map*>(root(kFreeSpaceMapRootIndex)),
2822         SKIP_WRITE_BARRIER);
2823     FreeSpace::cast(filler)->relaxed_write_size(size);
2824     if (clear_memory_mode == ClearFreedMemoryMode::kClearFreedMemory) {
2825       memset(reinterpret_cast<void*>(addr + 2 * kPointerSize),
2826              kClearedFreeMemoryValue, size - 2 * kPointerSize);
2827     }
2828   }
2829   if (clear_slots_mode == ClearRecordedSlots::kYes) {
2830     ClearRecordedSlotRange(addr, addr + size);
2831   }
2832 
2833   // At this point, we may be deserializing the heap from a snapshot, and
2834   // none of the maps have been created yet and are nullptr.
2835   DCHECK((filler->map() == nullptr && !deserialization_complete_) ||
2836          filler->map()->IsMap());
2837   return filler;
2838 }
2839 
2840 
CanMoveObjectStart(HeapObject * object)2841 bool Heap::CanMoveObjectStart(HeapObject* object) {
2842   if (!FLAG_move_object_start) return false;
2843 
2844   // Sampling heap profiler may have a reference to the object.
2845   if (isolate()->heap_profiler()->is_sampling_allocations()) return false;
2846 
2847   Address address = object->address();
2848 
2849   if (lo_space()->Contains(object)) return false;
2850 
2851   // We can move the object start if the page was already swept.
2852   return Page::FromAddress(address)->SweepingDone();
2853 }
2854 
IsImmovable(HeapObject * object)2855 bool Heap::IsImmovable(HeapObject* object) {
2856   MemoryChunk* chunk = MemoryChunk::FromAddress(object->address());
2857   return chunk->NeverEvacuate() || chunk->owner()->identity() == LO_SPACE;
2858 }
2859 
2860 #ifdef ENABLE_SLOW_DCHECKS
2861 namespace {
2862 
2863 class LeftTrimmerVerifierRootVisitor : public RootVisitor {
2864  public:
LeftTrimmerVerifierRootVisitor(FixedArrayBase * to_check)2865   explicit LeftTrimmerVerifierRootVisitor(FixedArrayBase* to_check)
2866       : to_check_(to_check) {}
2867 
VisitRootPointers(Root root,const char * description,Object ** start,Object ** end)2868   virtual void VisitRootPointers(Root root, const char* description,
2869                                  Object** start, Object** end) {
2870     for (Object** p = start; p < end; ++p) {
2871       DCHECK_NE(*p, to_check_);
2872     }
2873   }
2874 
2875  private:
2876   FixedArrayBase* to_check_;
2877 
2878   DISALLOW_COPY_AND_ASSIGN(LeftTrimmerVerifierRootVisitor);
2879 };
2880 }  // namespace
2881 #endif  // ENABLE_SLOW_DCHECKS
2882 
2883 namespace {
MayContainRecordedSlots(HeapObject * object)2884 bool MayContainRecordedSlots(HeapObject* object) {
2885   // New space object do not have recorded slots.
2886   if (MemoryChunk::FromHeapObject(object)->InNewSpace()) return false;
2887   // Whitelist objects that definitely do not have pointers.
2888   if (object->IsByteArray() || object->IsFixedDoubleArray()) return false;
2889   // Conservatively return true for other objects.
2890   return true;
2891 }
2892 }  // namespace
2893 
LeftTrimFixedArray(FixedArrayBase * object,int elements_to_trim)2894 FixedArrayBase* Heap::LeftTrimFixedArray(FixedArrayBase* object,
2895                                          int elements_to_trim) {
2896   if (elements_to_trim == 0) {
2897     // This simplifies reasoning in the rest of the function.
2898     return object;
2899   }
2900   CHECK_NOT_NULL(object);
2901   DCHECK(CanMoveObjectStart(object));
2902   // Add custom visitor to concurrent marker if new left-trimmable type
2903   // is added.
2904   DCHECK(object->IsFixedArray() || object->IsFixedDoubleArray());
2905   const int element_size = object->IsFixedArray() ? kPointerSize : kDoubleSize;
2906   const int bytes_to_trim = elements_to_trim * element_size;
2907   Map* map = object->map();
2908 
2909   // For now this trick is only applied to objects in new and paged space.
2910   // In large object space the object's start must coincide with chunk
2911   // and thus the trick is just not applicable.
2912   DCHECK(!lo_space()->Contains(object));
2913   DCHECK(object->map() != ReadOnlyRoots(this).fixed_cow_array_map());
2914 
2915   STATIC_ASSERT(FixedArrayBase::kMapOffset == 0);
2916   STATIC_ASSERT(FixedArrayBase::kLengthOffset == kPointerSize);
2917   STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize);
2918 
2919   const int len = object->length();
2920   DCHECK(elements_to_trim <= len);
2921 
2922   // Calculate location of new array start.
2923   Address old_start = object->address();
2924   Address new_start = old_start + bytes_to_trim;
2925 
2926   if (incremental_marking()->IsMarking()) {
2927     incremental_marking()->NotifyLeftTrimming(
2928         object, HeapObject::FromAddress(new_start));
2929   }
2930 
2931   // Technically in new space this write might be omitted (except for
2932   // debug mode which iterates through the heap), but to play safer
2933   // we still do it.
2934   HeapObject* filler =
2935       CreateFillerObjectAt(old_start, bytes_to_trim, ClearRecordedSlots::kYes);
2936 
2937   // Initialize header of the trimmed array. Since left trimming is only
2938   // performed on pages which are not concurrently swept creating a filler
2939   // object does not require synchronization.
2940   RELAXED_WRITE_FIELD(object, bytes_to_trim, map);
2941   RELAXED_WRITE_FIELD(object, bytes_to_trim + kPointerSize,
2942                       Smi::FromInt(len - elements_to_trim));
2943 
2944   FixedArrayBase* new_object =
2945       FixedArrayBase::cast(HeapObject::FromAddress(new_start));
2946 
2947   // Remove recorded slots for the new map and length offset.
2948   ClearRecordedSlot(new_object, HeapObject::RawField(new_object, 0));
2949   ClearRecordedSlot(new_object, HeapObject::RawField(
2950                                     new_object, FixedArrayBase::kLengthOffset));
2951 
2952   // Handle invalidated old-to-old slots.
2953   if (incremental_marking()->IsCompacting() &&
2954       MayContainRecordedSlots(new_object)) {
2955     // If the array was right-trimmed before, then it is registered in
2956     // the invalidated_slots.
2957     MemoryChunk::FromHeapObject(new_object)
2958         ->MoveObjectWithInvalidatedSlots(filler, new_object);
2959     // We have to clear slots in the free space to avoid stale old-to-old slots.
2960     // Note we cannot use ClearFreedMemoryMode of CreateFillerObjectAt because
2961     // we need pointer granularity writes to avoid race with the concurrent
2962     // marking.
2963     if (filler->Size() > FreeSpace::kSize) {
2964       MemsetPointer(HeapObject::RawField(filler, FreeSpace::kSize),
2965                     ReadOnlyRoots(this).undefined_value(),
2966                     (filler->Size() - FreeSpace::kSize) / kPointerSize);
2967     }
2968   }
2969   // Notify the heap profiler of change in object layout.
2970   OnMoveEvent(new_object, object, new_object->Size());
2971 
2972 #ifdef ENABLE_SLOW_DCHECKS
2973   if (FLAG_enable_slow_asserts) {
2974     // Make sure the stack or other roots (e.g., Handles) don't contain pointers
2975     // to the original FixedArray (which is now the filler object).
2976     LeftTrimmerVerifierRootVisitor root_visitor(object);
2977     IterateRoots(&root_visitor, VISIT_ALL);
2978   }
2979 #endif  // ENABLE_SLOW_DCHECKS
2980 
2981   return new_object;
2982 }
2983 
RightTrimFixedArray(FixedArrayBase * object,int elements_to_trim)2984 void Heap::RightTrimFixedArray(FixedArrayBase* object, int elements_to_trim) {
2985   const int len = object->length();
2986   DCHECK_LE(elements_to_trim, len);
2987   DCHECK_GE(elements_to_trim, 0);
2988 
2989   int bytes_to_trim;
2990   DCHECK(!object->IsFixedTypedArrayBase());
2991   if (object->IsByteArray()) {
2992     int new_size = ByteArray::SizeFor(len - elements_to_trim);
2993     bytes_to_trim = ByteArray::SizeFor(len) - new_size;
2994     DCHECK_GE(bytes_to_trim, 0);
2995   } else if (object->IsFixedArray()) {
2996     CHECK_NE(elements_to_trim, len);
2997     bytes_to_trim = elements_to_trim * kPointerSize;
2998   } else {
2999     DCHECK(object->IsFixedDoubleArray());
3000     CHECK_NE(elements_to_trim, len);
3001     bytes_to_trim = elements_to_trim * kDoubleSize;
3002   }
3003 
3004   CreateFillerForArray<FixedArrayBase>(object, elements_to_trim, bytes_to_trim);
3005 }
3006 
RightTrimWeakFixedArray(WeakFixedArray * object,int elements_to_trim)3007 void Heap::RightTrimWeakFixedArray(WeakFixedArray* object,
3008                                    int elements_to_trim) {
3009   // This function is safe to use only at the end of the mark compact
3010   // collection: When marking, we record the weak slots, and shrinking
3011   // invalidates them.
3012   DCHECK_EQ(gc_state(), MARK_COMPACT);
3013   CreateFillerForArray<WeakFixedArray>(object, elements_to_trim,
3014                                        elements_to_trim * kPointerSize);
3015 }
3016 
3017 template <typename T>
CreateFillerForArray(T * object,int elements_to_trim,int bytes_to_trim)3018 void Heap::CreateFillerForArray(T* object, int elements_to_trim,
3019                                 int bytes_to_trim) {
3020   DCHECK(object->IsFixedArrayBase() || object->IsByteArray() ||
3021          object->IsWeakFixedArray());
3022 
3023   // For now this trick is only applied to objects in new and paged space.
3024   DCHECK(object->map() != ReadOnlyRoots(this).fixed_cow_array_map());
3025 
3026   if (bytes_to_trim == 0) {
3027     DCHECK_EQ(elements_to_trim, 0);
3028     // No need to create filler and update live bytes counters.
3029     return;
3030   }
3031 
3032   // Calculate location of new array end.
3033   int old_size = object->Size();
3034   Address old_end = object->address() + old_size;
3035   Address new_end = old_end - bytes_to_trim;
3036 
3037   // Register the array as an object with invalidated old-to-old slots. We
3038   // cannot use NotifyObjectLayoutChange as it would mark the array black,
3039   // which is not safe for left-trimming because left-trimming re-pushes
3040   // only grey arrays onto the marking worklist.
3041   if (incremental_marking()->IsCompacting() &&
3042       MayContainRecordedSlots(object)) {
3043     // Ensure that the object survives because the InvalidatedSlotsFilter will
3044     // compute its size from its map during pointers updating phase.
3045     incremental_marking()->WhiteToGreyAndPush(object);
3046     MemoryChunk::FromHeapObject(object)->RegisterObjectWithInvalidatedSlots(
3047         object, old_size);
3048   }
3049 
3050   // Technically in new space this write might be omitted (except for
3051   // debug mode which iterates through the heap), but to play safer
3052   // we still do it.
3053   // We do not create a filler for objects in large object space.
3054   // TODO(hpayer): We should shrink the large object page if the size
3055   // of the object changed significantly.
3056   if (!lo_space()->Contains(object)) {
3057     HeapObject* filler =
3058         CreateFillerObjectAt(new_end, bytes_to_trim, ClearRecordedSlots::kYes);
3059     DCHECK_NOT_NULL(filler);
3060     // Clear the mark bits of the black area that belongs now to the filler.
3061     // This is an optimization. The sweeper will release black fillers anyway.
3062     if (incremental_marking()->black_allocation() &&
3063         incremental_marking()->marking_state()->IsBlackOrGrey(filler)) {
3064       Page* page = Page::FromAddress(new_end);
3065       incremental_marking()->marking_state()->bitmap(page)->ClearRange(
3066           page->AddressToMarkbitIndex(new_end),
3067           page->AddressToMarkbitIndex(new_end + bytes_to_trim));
3068     }
3069   }
3070 
3071   // Initialize header of the trimmed array. We are storing the new length
3072   // using release store after creating a filler for the left-over space to
3073   // avoid races with the sweeper thread.
3074   object->synchronized_set_length(object->length() - elements_to_trim);
3075 
3076   // Notify the heap object allocation tracker of change in object layout. The
3077   // array may not be moved during GC, and size has to be adjusted nevertheless.
3078   for (auto& tracker : allocation_trackers_) {
3079     tracker->UpdateObjectSizeEvent(object->address(), object->Size());
3080   }
3081 }
3082 
MakeHeapIterable()3083 void Heap::MakeHeapIterable() {
3084   mark_compact_collector()->EnsureSweepingCompleted();
3085 }
3086 
3087 
ComputeMutatorUtilization(double mutator_speed,double gc_speed)3088 static double ComputeMutatorUtilization(double mutator_speed, double gc_speed) {
3089   const double kMinMutatorUtilization = 0.0;
3090   const double kConservativeGcSpeedInBytesPerMillisecond = 200000;
3091   if (mutator_speed == 0) return kMinMutatorUtilization;
3092   if (gc_speed == 0) gc_speed = kConservativeGcSpeedInBytesPerMillisecond;
3093   // Derivation:
3094   // mutator_utilization = mutator_time / (mutator_time + gc_time)
3095   // mutator_time = 1 / mutator_speed
3096   // gc_time = 1 / gc_speed
3097   // mutator_utilization = (1 / mutator_speed) /
3098   //                       (1 / mutator_speed + 1 / gc_speed)
3099   // mutator_utilization = gc_speed / (mutator_speed + gc_speed)
3100   return gc_speed / (mutator_speed + gc_speed);
3101 }
3102 
3103 
YoungGenerationMutatorUtilization()3104 double Heap::YoungGenerationMutatorUtilization() {
3105   double mutator_speed = static_cast<double>(
3106       tracer()->NewSpaceAllocationThroughputInBytesPerMillisecond());
3107   double gc_speed =
3108       tracer()->ScavengeSpeedInBytesPerMillisecond(kForSurvivedObjects);
3109   double result = ComputeMutatorUtilization(mutator_speed, gc_speed);
3110   if (FLAG_trace_mutator_utilization) {
3111     isolate()->PrintWithTimestamp(
3112         "Young generation mutator utilization = %.3f ("
3113         "mutator_speed=%.f, gc_speed=%.f)\n",
3114         result, mutator_speed, gc_speed);
3115   }
3116   return result;
3117 }
3118 
3119 
OldGenerationMutatorUtilization()3120 double Heap::OldGenerationMutatorUtilization() {
3121   double mutator_speed = static_cast<double>(
3122       tracer()->OldGenerationAllocationThroughputInBytesPerMillisecond());
3123   double gc_speed = static_cast<double>(
3124       tracer()->CombinedMarkCompactSpeedInBytesPerMillisecond());
3125   double result = ComputeMutatorUtilization(mutator_speed, gc_speed);
3126   if (FLAG_trace_mutator_utilization) {
3127     isolate()->PrintWithTimestamp(
3128         "Old generation mutator utilization = %.3f ("
3129         "mutator_speed=%.f, gc_speed=%.f)\n",
3130         result, mutator_speed, gc_speed);
3131   }
3132   return result;
3133 }
3134 
3135 
HasLowYoungGenerationAllocationRate()3136 bool Heap::HasLowYoungGenerationAllocationRate() {
3137   const double high_mutator_utilization = 0.993;
3138   return YoungGenerationMutatorUtilization() > high_mutator_utilization;
3139 }
3140 
3141 
HasLowOldGenerationAllocationRate()3142 bool Heap::HasLowOldGenerationAllocationRate() {
3143   const double high_mutator_utilization = 0.993;
3144   return OldGenerationMutatorUtilization() > high_mutator_utilization;
3145 }
3146 
3147 
HasLowAllocationRate()3148 bool Heap::HasLowAllocationRate() {
3149   return HasLowYoungGenerationAllocationRate() &&
3150          HasLowOldGenerationAllocationRate();
3151 }
3152 
IsIneffectiveMarkCompact(size_t old_generation_size,double mutator_utilization)3153 bool Heap::IsIneffectiveMarkCompact(size_t old_generation_size,
3154                                     double mutator_utilization) {
3155   const double kHighHeapPercentage = 0.8;
3156   const double kLowMutatorUtilization = 0.4;
3157   return old_generation_size >=
3158              kHighHeapPercentage * max_old_generation_size_ &&
3159          mutator_utilization < kLowMutatorUtilization;
3160 }
3161 
CheckIneffectiveMarkCompact(size_t old_generation_size,double mutator_utilization)3162 void Heap::CheckIneffectiveMarkCompact(size_t old_generation_size,
3163                                        double mutator_utilization) {
3164   const int kMaxConsecutiveIneffectiveMarkCompacts = 4;
3165   if (!FLAG_detect_ineffective_gcs_near_heap_limit) return;
3166   if (!IsIneffectiveMarkCompact(old_generation_size, mutator_utilization)) {
3167     consecutive_ineffective_mark_compacts_ = 0;
3168     return;
3169   }
3170   ++consecutive_ineffective_mark_compacts_;
3171   if (consecutive_ineffective_mark_compacts_ ==
3172       kMaxConsecutiveIneffectiveMarkCompacts) {
3173     if (InvokeNearHeapLimitCallback()) {
3174       // The callback increased the heap limit.
3175       consecutive_ineffective_mark_compacts_ = 0;
3176       return;
3177     }
3178     FatalProcessOutOfMemory("Ineffective mark-compacts near heap limit");
3179   }
3180 }
3181 
HasHighFragmentation()3182 bool Heap::HasHighFragmentation() {
3183   size_t used = OldGenerationSizeOfObjects();
3184   size_t committed = CommittedOldGenerationMemory();
3185   return HasHighFragmentation(used, committed);
3186 }
3187 
HasHighFragmentation(size_t used,size_t committed)3188 bool Heap::HasHighFragmentation(size_t used, size_t committed) {
3189   const size_t kSlack = 16 * MB;
3190   // Fragmentation is high if committed > 2 * used + kSlack.
3191   // Rewrite the exression to avoid overflow.
3192   DCHECK_GE(committed, used);
3193   return committed - used > used + kSlack;
3194 }
3195 
ShouldOptimizeForMemoryUsage()3196 bool Heap::ShouldOptimizeForMemoryUsage() {
3197   const size_t kOldGenerationSlack = max_old_generation_size_ / 8;
3198   return FLAG_optimize_for_size || isolate()->IsIsolateInBackground() ||
3199          isolate()->IsMemorySavingsModeActive() || HighMemoryPressure() ||
3200          !CanExpandOldGeneration(kOldGenerationSlack);
3201 }
3202 
ActivateMemoryReducerIfNeeded()3203 void Heap::ActivateMemoryReducerIfNeeded() {
3204   // Activate memory reducer when switching to background if
3205   // - there was no mark compact since the start.
3206   // - the committed memory can be potentially reduced.
3207   // 2 pages for the old, code, and map space + 1 page for new space.
3208   const int kMinCommittedMemory = 7 * Page::kPageSize;
3209   if (ms_count_ == 0 && CommittedMemory() > kMinCommittedMemory &&
3210       isolate()->IsIsolateInBackground()) {
3211     MemoryReducer::Event event;
3212     event.type = MemoryReducer::kPossibleGarbage;
3213     event.time_ms = MonotonicallyIncreasingTimeInMs();
3214     memory_reducer_->NotifyPossibleGarbage(event);
3215   }
3216 }
3217 
ReduceNewSpaceSize()3218 void Heap::ReduceNewSpaceSize() {
3219   // TODO(ulan): Unify this constant with the similar constant in
3220   // GCIdleTimeHandler once the change is merged to 4.5.
3221   static const size_t kLowAllocationThroughput = 1000;
3222   const double allocation_throughput =
3223       tracer()->CurrentAllocationThroughputInBytesPerMillisecond();
3224 
3225   if (FLAG_predictable) return;
3226 
3227   if (ShouldReduceMemory() ||
3228       ((allocation_throughput != 0) &&
3229        (allocation_throughput < kLowAllocationThroughput))) {
3230     new_space_->Shrink();
3231     UncommitFromSpace();
3232   }
3233 }
3234 
FinalizeIncrementalMarkingIfComplete(GarbageCollectionReason gc_reason)3235 void Heap::FinalizeIncrementalMarkingIfComplete(
3236     GarbageCollectionReason gc_reason) {
3237   if (incremental_marking()->IsMarking() &&
3238       (incremental_marking()->IsReadyToOverApproximateWeakClosure() ||
3239        (!incremental_marking()->finalize_marking_completed() &&
3240         mark_compact_collector()->marking_worklist()->IsEmpty() &&
3241         local_embedder_heap_tracer()->ShouldFinalizeIncrementalMarking()))) {
3242     FinalizeIncrementalMarkingIncrementally(gc_reason);
3243   } else if (incremental_marking()->IsComplete() ||
3244              (mark_compact_collector()->marking_worklist()->IsEmpty() &&
3245               local_embedder_heap_tracer()
3246                   ->ShouldFinalizeIncrementalMarking())) {
3247     CollectAllGarbage(current_gc_flags_, gc_reason, current_gc_callback_flags_);
3248   }
3249 }
3250 
FinalizeIncrementalMarkingAtomically(GarbageCollectionReason gc_reason)3251 void Heap::FinalizeIncrementalMarkingAtomically(
3252     GarbageCollectionReason gc_reason) {
3253   DCHECK(!incremental_marking()->IsStopped());
3254   CollectAllGarbage(current_gc_flags_, gc_reason, current_gc_callback_flags_);
3255 }
3256 
FinalizeIncrementalMarkingIncrementally(GarbageCollectionReason gc_reason)3257 void Heap::FinalizeIncrementalMarkingIncrementally(
3258     GarbageCollectionReason gc_reason) {
3259   if (FLAG_trace_incremental_marking) {
3260     isolate()->PrintWithTimestamp(
3261         "[IncrementalMarking] (%s).\n",
3262         Heap::GarbageCollectionReasonToString(gc_reason));
3263   }
3264 
3265   HistogramTimerScope incremental_marking_scope(
3266       isolate()->counters()->gc_incremental_marking_finalize());
3267   TRACE_EVENT0("v8", "V8.GCIncrementalMarkingFinalize");
3268   TRACE_GC(tracer(), GCTracer::Scope::MC_INCREMENTAL_FINALIZE);
3269 
3270   {
3271     GCCallbacksScope scope(this);
3272     if (scope.CheckReenter()) {
3273       AllowHeapAllocation allow_allocation;
3274       TRACE_GC(tracer(), GCTracer::Scope::MC_INCREMENTAL_EXTERNAL_PROLOGUE);
3275       VMState<EXTERNAL> state(isolate_);
3276       HandleScope handle_scope(isolate_);
3277       CallGCPrologueCallbacks(kGCTypeIncrementalMarking, kNoGCCallbackFlags);
3278     }
3279   }
3280   incremental_marking()->FinalizeIncrementally();
3281   {
3282     GCCallbacksScope scope(this);
3283     if (scope.CheckReenter()) {
3284       AllowHeapAllocation allow_allocation;
3285       TRACE_GC(tracer(), GCTracer::Scope::MC_INCREMENTAL_EXTERNAL_EPILOGUE);
3286       VMState<EXTERNAL> state(isolate_);
3287       HandleScope handle_scope(isolate_);
3288       CallGCEpilogueCallbacks(kGCTypeIncrementalMarking, kNoGCCallbackFlags);
3289     }
3290   }
3291 }
3292 
RegisterDeserializedObjectsForBlackAllocation(Reservation * reservations,const std::vector<HeapObject * > & large_objects,const std::vector<Address> & maps)3293 void Heap::RegisterDeserializedObjectsForBlackAllocation(
3294     Reservation* reservations, const std::vector<HeapObject*>& large_objects,
3295     const std::vector<Address>& maps) {
3296   // TODO(ulan): pause black allocation during deserialization to avoid
3297   // iterating all these objects in one go.
3298 
3299   if (!incremental_marking()->black_allocation()) return;
3300 
3301   // Iterate black objects in old space, code space, map space, and large
3302   // object space for side effects.
3303   IncrementalMarking::MarkingState* marking_state =
3304       incremental_marking()->marking_state();
3305   for (int i = OLD_SPACE; i < Serializer<>::kNumberOfSpaces; i++) {
3306     const Heap::Reservation& res = reservations[i];
3307     for (auto& chunk : res) {
3308       Address addr = chunk.start;
3309       while (addr < chunk.end) {
3310         HeapObject* obj = HeapObject::FromAddress(addr);
3311         // Objects can have any color because incremental marking can
3312         // start in the middle of Heap::ReserveSpace().
3313         if (marking_state->IsBlack(obj)) {
3314           incremental_marking()->ProcessBlackAllocatedObject(obj);
3315         }
3316         addr += obj->Size();
3317       }
3318     }
3319   }
3320   // We potentially deserialized wrappers which require registering with the
3321   // embedder as the marker will not find them.
3322   local_embedder_heap_tracer()->RegisterWrappersWithRemoteTracer();
3323 
3324   // Large object space doesn't use reservations, so it needs custom handling.
3325   for (HeapObject* object : large_objects) {
3326     incremental_marking()->ProcessBlackAllocatedObject(object);
3327   }
3328 
3329   // Map space doesn't use reservations, so it needs custom handling.
3330   for (Address addr : maps) {
3331     incremental_marking()->ProcessBlackAllocatedObject(
3332         HeapObject::FromAddress(addr));
3333   }
3334 }
3335 
NotifyObjectLayoutChange(HeapObject * object,int size,const DisallowHeapAllocation &)3336 void Heap::NotifyObjectLayoutChange(HeapObject* object, int size,
3337                                     const DisallowHeapAllocation&) {
3338   if (incremental_marking()->IsMarking()) {
3339     incremental_marking()->MarkBlackAndPush(object);
3340     if (incremental_marking()->IsCompacting() &&
3341         MayContainRecordedSlots(object)) {
3342       MemoryChunk::FromHeapObject(object)->RegisterObjectWithInvalidatedSlots(
3343           object, size);
3344     }
3345   }
3346 #ifdef VERIFY_HEAP
3347   if (FLAG_verify_heap) {
3348     DCHECK_NULL(pending_layout_change_object_);
3349     pending_layout_change_object_ = object;
3350   }
3351 #endif
3352 }
3353 
3354 #ifdef VERIFY_HEAP
3355 // Helper class for collecting slot addresses.
3356 class SlotCollectingVisitor final : public ObjectVisitor {
3357  public:
VisitPointers(HeapObject * host,Object ** start,Object ** end)3358   void VisitPointers(HeapObject* host, Object** start, Object** end) override {
3359     VisitPointers(host, reinterpret_cast<MaybeObject**>(start),
3360                   reinterpret_cast<MaybeObject**>(end));
3361   }
VisitPointers(HeapObject * host,MaybeObject ** start,MaybeObject ** end)3362   void VisitPointers(HeapObject* host, MaybeObject** start,
3363                      MaybeObject** end) final {
3364     for (MaybeObject** p = start; p < end; p++) {
3365       slots_.push_back(p);
3366     }
3367   }
3368 
number_of_slots()3369   int number_of_slots() { return static_cast<int>(slots_.size()); }
3370 
slot(int i)3371   MaybeObject** slot(int i) { return slots_[i]; }
3372 
3373  private:
3374   std::vector<MaybeObject**> slots_;
3375 };
3376 
VerifyObjectLayoutChange(HeapObject * object,Map * new_map)3377 void Heap::VerifyObjectLayoutChange(HeapObject* object, Map* new_map) {
3378   if (!FLAG_verify_heap) return;
3379 
3380   // Check that Heap::NotifyObjectLayout was called for object transitions
3381   // that are not safe for concurrent marking.
3382   // If you see this check triggering for a freshly allocated object,
3383   // use object->set_map_after_allocation() to initialize its map.
3384   if (pending_layout_change_object_ == nullptr) {
3385     if (object->IsJSObject()) {
3386       DCHECK(!object->map()->TransitionRequiresSynchronizationWithGC(new_map));
3387     } else {
3388       // Check that the set of slots before and after the transition match.
3389       SlotCollectingVisitor old_visitor;
3390       object->IterateFast(&old_visitor);
3391       MapWord old_map_word = object->map_word();
3392       // Temporarily set the new map to iterate new slots.
3393       object->set_map_word(MapWord::FromMap(new_map));
3394       SlotCollectingVisitor new_visitor;
3395       object->IterateFast(&new_visitor);
3396       // Restore the old map.
3397       object->set_map_word(old_map_word);
3398       DCHECK_EQ(new_visitor.number_of_slots(), old_visitor.number_of_slots());
3399       for (int i = 0; i < new_visitor.number_of_slots(); i++) {
3400         DCHECK_EQ(new_visitor.slot(i), old_visitor.slot(i));
3401       }
3402     }
3403   } else {
3404     DCHECK_EQ(pending_layout_change_object_, object);
3405     pending_layout_change_object_ = nullptr;
3406   }
3407 }
3408 #endif
3409 
ComputeHeapState()3410 GCIdleTimeHeapState Heap::ComputeHeapState() {
3411   GCIdleTimeHeapState heap_state;
3412   heap_state.contexts_disposed = contexts_disposed_;
3413   heap_state.contexts_disposal_rate =
3414       tracer()->ContextDisposalRateInMilliseconds();
3415   heap_state.size_of_objects = static_cast<size_t>(SizeOfObjects());
3416   heap_state.incremental_marking_stopped = incremental_marking()->IsStopped();
3417   return heap_state;
3418 }
3419 
3420 
PerformIdleTimeAction(GCIdleTimeAction action,GCIdleTimeHeapState heap_state,double deadline_in_ms)3421 bool Heap::PerformIdleTimeAction(GCIdleTimeAction action,
3422                                  GCIdleTimeHeapState heap_state,
3423                                  double deadline_in_ms) {
3424   bool result = false;
3425   switch (action.type) {
3426     case DONE:
3427       result = true;
3428       break;
3429     case DO_INCREMENTAL_STEP: {
3430       const double remaining_idle_time_in_ms =
3431           incremental_marking()->AdvanceIncrementalMarking(
3432               deadline_in_ms, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
3433               StepOrigin::kTask);
3434       if (remaining_idle_time_in_ms > 0.0) {
3435         FinalizeIncrementalMarkingIfComplete(
3436             GarbageCollectionReason::kFinalizeMarkingViaTask);
3437       }
3438       result = incremental_marking()->IsStopped();
3439       break;
3440     }
3441     case DO_FULL_GC: {
3442       DCHECK_LT(0, contexts_disposed_);
3443       HistogramTimerScope scope(isolate_->counters()->gc_context());
3444       TRACE_EVENT0("v8", "V8.GCContext");
3445       CollectAllGarbage(kNoGCFlags, GarbageCollectionReason::kContextDisposal);
3446       break;
3447     }
3448     case DO_NOTHING:
3449       break;
3450   }
3451 
3452   return result;
3453 }
3454 
IdleNotificationEpilogue(GCIdleTimeAction action,GCIdleTimeHeapState heap_state,double start_ms,double deadline_in_ms)3455 void Heap::IdleNotificationEpilogue(GCIdleTimeAction action,
3456                                     GCIdleTimeHeapState heap_state,
3457                                     double start_ms, double deadline_in_ms) {
3458   double idle_time_in_ms = deadline_in_ms - start_ms;
3459   double current_time = MonotonicallyIncreasingTimeInMs();
3460   last_idle_notification_time_ = current_time;
3461   double deadline_difference = deadline_in_ms - current_time;
3462 
3463   contexts_disposed_ = 0;
3464 
3465   if ((FLAG_trace_idle_notification && action.type > DO_NOTHING) ||
3466       FLAG_trace_idle_notification_verbose) {
3467     isolate_->PrintWithTimestamp(
3468         "Idle notification: requested idle time %.2f ms, used idle time %.2f "
3469         "ms, deadline usage %.2f ms [",
3470         idle_time_in_ms, idle_time_in_ms - deadline_difference,
3471         deadline_difference);
3472     action.Print();
3473     PrintF("]");
3474     if (FLAG_trace_idle_notification_verbose) {
3475       PrintF("[");
3476       heap_state.Print();
3477       PrintF("]");
3478     }
3479     PrintF("\n");
3480   }
3481 }
3482 
3483 
MonotonicallyIncreasingTimeInMs()3484 double Heap::MonotonicallyIncreasingTimeInMs() {
3485   return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
3486          static_cast<double>(base::Time::kMillisecondsPerSecond);
3487 }
3488 
3489 
IdleNotification(int idle_time_in_ms)3490 bool Heap::IdleNotification(int idle_time_in_ms) {
3491   return IdleNotification(
3492       V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() +
3493       (static_cast<double>(idle_time_in_ms) /
3494        static_cast<double>(base::Time::kMillisecondsPerSecond)));
3495 }
3496 
3497 
IdleNotification(double deadline_in_seconds)3498 bool Heap::IdleNotification(double deadline_in_seconds) {
3499   CHECK(HasBeenSetUp());
3500   double deadline_in_ms =
3501       deadline_in_seconds *
3502       static_cast<double>(base::Time::kMillisecondsPerSecond);
3503   HistogramTimerScope idle_notification_scope(
3504       isolate_->counters()->gc_idle_notification());
3505   TRACE_EVENT0("v8", "V8.GCIdleNotification");
3506   double start_ms = MonotonicallyIncreasingTimeInMs();
3507   double idle_time_in_ms = deadline_in_ms - start_ms;
3508 
3509   tracer()->SampleAllocation(start_ms, NewSpaceAllocationCounter(),
3510                              OldGenerationAllocationCounter());
3511 
3512   GCIdleTimeHeapState heap_state = ComputeHeapState();
3513 
3514   GCIdleTimeAction action =
3515       gc_idle_time_handler_->Compute(idle_time_in_ms, heap_state);
3516 
3517   bool result = PerformIdleTimeAction(action, heap_state, deadline_in_ms);
3518 
3519   IdleNotificationEpilogue(action, heap_state, start_ms, deadline_in_ms);
3520   return result;
3521 }
3522 
3523 
RecentIdleNotificationHappened()3524 bool Heap::RecentIdleNotificationHappened() {
3525   return (last_idle_notification_time_ +
3526           GCIdleTimeHandler::kMaxScheduledIdleTime) >
3527          MonotonicallyIncreasingTimeInMs();
3528 }
3529 
3530 class MemoryPressureInterruptTask : public CancelableTask {
3531  public:
MemoryPressureInterruptTask(Heap * heap)3532   explicit MemoryPressureInterruptTask(Heap* heap)
3533       : CancelableTask(heap->isolate()), heap_(heap) {}
3534 
~MemoryPressureInterruptTask()3535   virtual ~MemoryPressureInterruptTask() {}
3536 
3537  private:
3538   // v8::internal::CancelableTask overrides.
RunInternal()3539   void RunInternal() override { heap_->CheckMemoryPressure(); }
3540 
3541   Heap* heap_;
3542   DISALLOW_COPY_AND_ASSIGN(MemoryPressureInterruptTask);
3543 };
3544 
CheckMemoryPressure()3545 void Heap::CheckMemoryPressure() {
3546   if (HighMemoryPressure()) {
3547     // The optimizing compiler may be unnecessarily holding on to memory.
3548     isolate()->AbortConcurrentOptimization(BlockingBehavior::kDontBlock);
3549   }
3550   MemoryPressureLevel memory_pressure_level = memory_pressure_level_;
3551   // Reset the memory pressure level to avoid recursive GCs triggered by
3552   // CheckMemoryPressure from AdjustAmountOfExternalMemory called by
3553   // the finalizers.
3554   memory_pressure_level_ = MemoryPressureLevel::kNone;
3555   if (memory_pressure_level == MemoryPressureLevel::kCritical) {
3556     CollectGarbageOnMemoryPressure();
3557   } else if (memory_pressure_level == MemoryPressureLevel::kModerate) {
3558     if (FLAG_incremental_marking && incremental_marking()->IsStopped()) {
3559       StartIncrementalMarking(kReduceMemoryFootprintMask,
3560                               GarbageCollectionReason::kMemoryPressure);
3561     }
3562   }
3563   if (memory_reducer_) {
3564     MemoryReducer::Event event;
3565     event.type = MemoryReducer::kPossibleGarbage;
3566     event.time_ms = MonotonicallyIncreasingTimeInMs();
3567     memory_reducer_->NotifyPossibleGarbage(event);
3568   }
3569 }
3570 
CollectGarbageOnMemoryPressure()3571 void Heap::CollectGarbageOnMemoryPressure() {
3572   const int kGarbageThresholdInBytes = 8 * MB;
3573   const double kGarbageThresholdAsFractionOfTotalMemory = 0.1;
3574   // This constant is the maximum response time in RAIL performance model.
3575   const double kMaxMemoryPressurePauseMs = 100;
3576 
3577   double start = MonotonicallyIncreasingTimeInMs();
3578   CollectAllGarbage(kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask,
3579                     GarbageCollectionReason::kMemoryPressure,
3580                     kGCCallbackFlagCollectAllAvailableGarbage);
3581   double end = MonotonicallyIncreasingTimeInMs();
3582 
3583   // Estimate how much memory we can free.
3584   int64_t potential_garbage =
3585       (CommittedMemory() - SizeOfObjects()) + external_memory_;
3586   // If we can potentially free large amount of memory, then start GC right
3587   // away instead of waiting for memory reducer.
3588   if (potential_garbage >= kGarbageThresholdInBytes &&
3589       potential_garbage >=
3590           CommittedMemory() * kGarbageThresholdAsFractionOfTotalMemory) {
3591     // If we spent less than half of the time budget, then perform full GC
3592     // Otherwise, start incremental marking.
3593     if (end - start < kMaxMemoryPressurePauseMs / 2) {
3594       CollectAllGarbage(
3595           kReduceMemoryFootprintMask | kAbortIncrementalMarkingMask,
3596           GarbageCollectionReason::kMemoryPressure,
3597           kGCCallbackFlagCollectAllAvailableGarbage);
3598     } else {
3599       if (FLAG_incremental_marking && incremental_marking()->IsStopped()) {
3600         StartIncrementalMarking(kReduceMemoryFootprintMask,
3601                                 GarbageCollectionReason::kMemoryPressure);
3602       }
3603     }
3604   }
3605 }
3606 
MemoryPressureNotification(MemoryPressureLevel level,bool is_isolate_locked)3607 void Heap::MemoryPressureNotification(MemoryPressureLevel level,
3608                                       bool is_isolate_locked) {
3609   MemoryPressureLevel previous = memory_pressure_level_;
3610   memory_pressure_level_ = level;
3611   if ((previous != MemoryPressureLevel::kCritical &&
3612        level == MemoryPressureLevel::kCritical) ||
3613       (previous == MemoryPressureLevel::kNone &&
3614        level == MemoryPressureLevel::kModerate)) {
3615     if (is_isolate_locked) {
3616       CheckMemoryPressure();
3617     } else {
3618       ExecutionAccess access(isolate());
3619       isolate()->stack_guard()->RequestGC();
3620       V8::GetCurrentPlatform()->CallOnForegroundThread(
3621           reinterpret_cast<v8::Isolate*>(isolate()),
3622           new MemoryPressureInterruptTask(this));
3623     }
3624   }
3625 }
3626 
AddNearHeapLimitCallback(v8::NearHeapLimitCallback callback,void * data)3627 void Heap::AddNearHeapLimitCallback(v8::NearHeapLimitCallback callback,
3628                                     void* data) {
3629   const size_t kMaxCallbacks = 100;
3630   CHECK_LT(near_heap_limit_callbacks_.size(), kMaxCallbacks);
3631   for (auto callback_data : near_heap_limit_callbacks_) {
3632     CHECK_NE(callback_data.first, callback);
3633   }
3634   near_heap_limit_callbacks_.push_back(std::make_pair(callback, data));
3635 }
3636 
RemoveNearHeapLimitCallback(v8::NearHeapLimitCallback callback,size_t heap_limit)3637 void Heap::RemoveNearHeapLimitCallback(v8::NearHeapLimitCallback callback,
3638                                        size_t heap_limit) {
3639   for (size_t i = 0; i < near_heap_limit_callbacks_.size(); i++) {
3640     if (near_heap_limit_callbacks_[i].first == callback) {
3641       near_heap_limit_callbacks_.erase(near_heap_limit_callbacks_.begin() + i);
3642       if (heap_limit) {
3643         RestoreHeapLimit(heap_limit);
3644       }
3645       return;
3646     }
3647   }
3648   UNREACHABLE();
3649 }
3650 
InvokeNearHeapLimitCallback()3651 bool Heap::InvokeNearHeapLimitCallback() {
3652   if (near_heap_limit_callbacks_.size() > 0) {
3653     HandleScope scope(isolate());
3654     v8::NearHeapLimitCallback callback =
3655         near_heap_limit_callbacks_.back().first;
3656     void* data = near_heap_limit_callbacks_.back().second;
3657     size_t heap_limit = callback(data, max_old_generation_size_,
3658                                  initial_max_old_generation_size_);
3659     if (heap_limit > max_old_generation_size_) {
3660       max_old_generation_size_ = heap_limit;
3661       return true;
3662     }
3663   }
3664   return false;
3665 }
3666 
CollectCodeStatistics()3667 void Heap::CollectCodeStatistics() {
3668   TRACE_EVENT0("v8", "Heap::CollectCodeStatistics");
3669   CodeStatistics::ResetCodeAndMetadataStatistics(isolate());
3670   // We do not look for code in new space, or map space.  If code
3671   // somehow ends up in those spaces, we would miss it here.
3672   CodeStatistics::CollectCodeStatistics(code_space_, isolate());
3673   CodeStatistics::CollectCodeStatistics(old_space_, isolate());
3674   CodeStatistics::CollectCodeStatistics(lo_space_, isolate());
3675 }
3676 
3677 #ifdef DEBUG
3678 
Print()3679 void Heap::Print() {
3680   if (!HasBeenSetUp()) return;
3681   isolate()->PrintStack(stdout);
3682 
3683   for (SpaceIterator it(this); it.has_next();) {
3684     it.next()->Print();
3685   }
3686 }
3687 
3688 
ReportCodeStatistics(const char * title)3689 void Heap::ReportCodeStatistics(const char* title) {
3690   PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title);
3691   CollectCodeStatistics();
3692   CodeStatistics::ReportCodeStatistics(isolate());
3693 }
3694 
3695 #endif  // DEBUG
3696 
GarbageCollectionReasonToString(GarbageCollectionReason gc_reason)3697 const char* Heap::GarbageCollectionReasonToString(
3698     GarbageCollectionReason gc_reason) {
3699   switch (gc_reason) {
3700     case GarbageCollectionReason::kAllocationFailure:
3701       return "allocation failure";
3702     case GarbageCollectionReason::kAllocationLimit:
3703       return "allocation limit";
3704     case GarbageCollectionReason::kContextDisposal:
3705       return "context disposal";
3706     case GarbageCollectionReason::kCountersExtension:
3707       return "counters extension";
3708     case GarbageCollectionReason::kDebugger:
3709       return "debugger";
3710     case GarbageCollectionReason::kDeserializer:
3711       return "deserialize";
3712     case GarbageCollectionReason::kExternalMemoryPressure:
3713       return "external memory pressure";
3714     case GarbageCollectionReason::kFinalizeMarkingViaStackGuard:
3715       return "finalize incremental marking via stack guard";
3716     case GarbageCollectionReason::kFinalizeMarkingViaTask:
3717       return "finalize incremental marking via task";
3718     case GarbageCollectionReason::kFullHashtable:
3719       return "full hash-table";
3720     case GarbageCollectionReason::kHeapProfiler:
3721       return "heap profiler";
3722     case GarbageCollectionReason::kIdleTask:
3723       return "idle task";
3724     case GarbageCollectionReason::kLastResort:
3725       return "last resort";
3726     case GarbageCollectionReason::kLowMemoryNotification:
3727       return "low memory notification";
3728     case GarbageCollectionReason::kMakeHeapIterable:
3729       return "make heap iterable";
3730     case GarbageCollectionReason::kMemoryPressure:
3731       return "memory pressure";
3732     case GarbageCollectionReason::kMemoryReducer:
3733       return "memory reducer";
3734     case GarbageCollectionReason::kRuntime:
3735       return "runtime";
3736     case GarbageCollectionReason::kSamplingProfiler:
3737       return "sampling profiler";
3738     case GarbageCollectionReason::kSnapshotCreator:
3739       return "snapshot creator";
3740     case GarbageCollectionReason::kTesting:
3741       return "testing";
3742     case GarbageCollectionReason::kExternalFinalize:
3743       return "external finalize";
3744     case GarbageCollectionReason::kUnknown:
3745       return "unknown";
3746   }
3747   UNREACHABLE();
3748 }
3749 
Contains(HeapObject * value)3750 bool Heap::Contains(HeapObject* value) {
3751   if (memory_allocator()->IsOutsideAllocatedSpace(value->address())) {
3752     return false;
3753   }
3754   return HasBeenSetUp() &&
3755          (new_space_->ToSpaceContains(value) || old_space_->Contains(value) ||
3756           code_space_->Contains(value) || map_space_->Contains(value) ||
3757           lo_space_->Contains(value) || read_only_space_->Contains(value));
3758 }
3759 
ContainsSlow(Address addr)3760 bool Heap::ContainsSlow(Address addr) {
3761   if (memory_allocator()->IsOutsideAllocatedSpace(addr)) {
3762     return false;
3763   }
3764   return HasBeenSetUp() &&
3765          (new_space_->ToSpaceContainsSlow(addr) ||
3766           old_space_->ContainsSlow(addr) || code_space_->ContainsSlow(addr) ||
3767           map_space_->ContainsSlow(addr) || lo_space_->ContainsSlow(addr) ||
3768           read_only_space_->Contains(addr));
3769 }
3770 
InSpace(HeapObject * value,AllocationSpace space)3771 bool Heap::InSpace(HeapObject* value, AllocationSpace space) {
3772   if (memory_allocator()->IsOutsideAllocatedSpace(value->address())) {
3773     return false;
3774   }
3775   if (!HasBeenSetUp()) return false;
3776 
3777   switch (space) {
3778     case NEW_SPACE:
3779       return new_space_->ToSpaceContains(value);
3780     case OLD_SPACE:
3781       return old_space_->Contains(value);
3782     case CODE_SPACE:
3783       return code_space_->Contains(value);
3784     case MAP_SPACE:
3785       return map_space_->Contains(value);
3786     case LO_SPACE:
3787       return lo_space_->Contains(value);
3788     case NEW_LO_SPACE:
3789       return new_lo_space_->Contains(value);
3790     case RO_SPACE:
3791       return read_only_space_->Contains(value);
3792   }
3793   UNREACHABLE();
3794 }
3795 
InSpaceSlow(Address addr,AllocationSpace space)3796 bool Heap::InSpaceSlow(Address addr, AllocationSpace space) {
3797   if (memory_allocator()->IsOutsideAllocatedSpace(addr)) {
3798     return false;
3799   }
3800   if (!HasBeenSetUp()) return false;
3801 
3802   switch (space) {
3803     case NEW_SPACE:
3804       return new_space_->ToSpaceContainsSlow(addr);
3805     case OLD_SPACE:
3806       return old_space_->ContainsSlow(addr);
3807     case CODE_SPACE:
3808       return code_space_->ContainsSlow(addr);
3809     case MAP_SPACE:
3810       return map_space_->ContainsSlow(addr);
3811     case LO_SPACE:
3812       return lo_space_->ContainsSlow(addr);
3813     case NEW_LO_SPACE:
3814       return new_lo_space_->ContainsSlow(addr);
3815     case RO_SPACE:
3816       return read_only_space_->ContainsSlow(addr);
3817   }
3818   UNREACHABLE();
3819 }
3820 
IsValidAllocationSpace(AllocationSpace space)3821 bool Heap::IsValidAllocationSpace(AllocationSpace space) {
3822   switch (space) {
3823     case NEW_SPACE:
3824     case OLD_SPACE:
3825     case CODE_SPACE:
3826     case MAP_SPACE:
3827     case LO_SPACE:
3828     case NEW_LO_SPACE:
3829     case RO_SPACE:
3830       return true;
3831     default:
3832       return false;
3833   }
3834 }
3835 
3836 
RootIsImmortalImmovable(int root_index)3837 bool Heap::RootIsImmortalImmovable(int root_index) {
3838   switch (root_index) {
3839 #define IMMORTAL_IMMOVABLE_ROOT(name) case Heap::k##name##RootIndex:
3840     IMMORTAL_IMMOVABLE_ROOT_LIST(IMMORTAL_IMMOVABLE_ROOT)
3841 #undef IMMORTAL_IMMOVABLE_ROOT
3842 #define INTERNALIZED_STRING(name, value) case Heap::k##name##RootIndex:
3843     INTERNALIZED_STRING_LIST(INTERNALIZED_STRING)
3844 #undef INTERNALIZED_STRING
3845 #define STRING_TYPE(NAME, size, name, Name) case Heap::k##Name##MapRootIndex:
3846     STRING_TYPE_LIST(STRING_TYPE)
3847 #undef STRING_TYPE
3848     return true;
3849     default:
3850       return false;
3851   }
3852 }
3853 
3854 #ifdef VERIFY_HEAP
3855 class VerifyReadOnlyPointersVisitor : public VerifyPointersVisitor {
3856  public:
VerifyReadOnlyPointersVisitor(Heap * heap)3857   explicit VerifyReadOnlyPointersVisitor(Heap* heap)
3858       : VerifyPointersVisitor(heap) {}
3859 
3860  protected:
VerifyPointers(HeapObject * host,MaybeObject ** start,MaybeObject ** end)3861   void VerifyPointers(HeapObject* host, MaybeObject** start,
3862                       MaybeObject** end) override {
3863     if (host != nullptr) {
3864       CHECK(heap_->InReadOnlySpace(host->map()));
3865     }
3866     VerifyPointersVisitor::VerifyPointers(host, start, end);
3867 
3868     for (MaybeObject** current = start; current < end; current++) {
3869       HeapObject* object;
3870       if ((*current)->ToStrongOrWeakHeapObject(&object)) {
3871         CHECK(heap_->InReadOnlySpace(object));
3872       }
3873     }
3874   }
3875 };
3876 
Verify()3877 void Heap::Verify() {
3878   CHECK(HasBeenSetUp());
3879   HandleScope scope(isolate());
3880 
3881   // We have to wait here for the sweeper threads to have an iterable heap.
3882   mark_compact_collector()->EnsureSweepingCompleted();
3883 
3884   VerifyPointersVisitor visitor(this);
3885   IterateRoots(&visitor, VISIT_ONLY_STRONG);
3886 
3887   VerifySmisVisitor smis_visitor;
3888   IterateSmiRoots(&smis_visitor);
3889 
3890   new_space_->Verify(isolate());
3891 
3892   old_space_->Verify(isolate(), &visitor);
3893   map_space_->Verify(isolate(), &visitor);
3894 
3895   VerifyPointersVisitor no_dirty_regions_visitor(this);
3896   code_space_->Verify(isolate(), &no_dirty_regions_visitor);
3897 
3898   lo_space_->Verify(isolate());
3899 
3900   VerifyReadOnlyPointersVisitor read_only_visitor(this);
3901   read_only_space_->Verify(isolate(), &read_only_visitor);
3902 }
3903 
3904 class SlotVerifyingVisitor : public ObjectVisitor {
3905  public:
SlotVerifyingVisitor(std::set<Address> * untyped,std::set<std::pair<SlotType,Address>> * typed)3906   SlotVerifyingVisitor(std::set<Address>* untyped,
3907                        std::set<std::pair<SlotType, Address> >* typed)
3908       : untyped_(untyped), typed_(typed) {}
3909 
3910   virtual bool ShouldHaveBeenRecorded(HeapObject* host,
3911                                       MaybeObject* target) = 0;
3912 
VisitPointers(HeapObject * host,Object ** start,Object ** end)3913   void VisitPointers(HeapObject* host, Object** start, Object** end) override {
3914 #ifdef DEBUG
3915     for (Object** slot = start; slot < end; slot++) {
3916       DCHECK(!HasWeakHeapObjectTag(*slot));
3917     }
3918 #endif  // DEBUG
3919     VisitPointers(host, reinterpret_cast<MaybeObject**>(start),
3920                   reinterpret_cast<MaybeObject**>(end));
3921   }
3922 
VisitPointers(HeapObject * host,MaybeObject ** start,MaybeObject ** end)3923   void VisitPointers(HeapObject* host, MaybeObject** start,
3924                      MaybeObject** end) final {
3925     for (MaybeObject** slot = start; slot < end; slot++) {
3926       if (ShouldHaveBeenRecorded(host, *slot)) {
3927         CHECK_GT(untyped_->count(reinterpret_cast<Address>(slot)), 0);
3928       }
3929     }
3930   }
3931 
VisitCodeTarget(Code * host,RelocInfo * rinfo)3932   void VisitCodeTarget(Code* host, RelocInfo* rinfo) override {
3933     Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
3934     if (ShouldHaveBeenRecorded(host, MaybeObject::FromObject(target))) {
3935       CHECK(
3936           InTypedSet(CODE_TARGET_SLOT, rinfo->pc()) ||
3937           (rinfo->IsInConstantPool() &&
3938            InTypedSet(CODE_ENTRY_SLOT, rinfo->constant_pool_entry_address())));
3939     }
3940   }
3941 
VisitEmbeddedPointer(Code * host,RelocInfo * rinfo)3942   void VisitEmbeddedPointer(Code* host, RelocInfo* rinfo) override {
3943     Object* target = rinfo->target_object();
3944     if (ShouldHaveBeenRecorded(host, MaybeObject::FromObject(target))) {
3945       CHECK(InTypedSet(EMBEDDED_OBJECT_SLOT, rinfo->pc()) ||
3946             (rinfo->IsInConstantPool() &&
3947              InTypedSet(OBJECT_SLOT, rinfo->constant_pool_entry_address())));
3948     }
3949   }
3950 
3951  private:
InTypedSet(SlotType type,Address slot)3952   bool InTypedSet(SlotType type, Address slot) {
3953     return typed_->count(std::make_pair(type, slot)) > 0;
3954   }
3955   std::set<Address>* untyped_;
3956   std::set<std::pair<SlotType, Address> >* typed_;
3957 };
3958 
3959 class OldToNewSlotVerifyingVisitor : public SlotVerifyingVisitor {
3960  public:
OldToNewSlotVerifyingVisitor(std::set<Address> * untyped,std::set<std::pair<SlotType,Address>> * typed)3961   OldToNewSlotVerifyingVisitor(std::set<Address>* untyped,
3962                                std::set<std::pair<SlotType, Address>>* typed)
3963       : SlotVerifyingVisitor(untyped, typed) {}
3964 
ShouldHaveBeenRecorded(HeapObject * host,MaybeObject * target)3965   bool ShouldHaveBeenRecorded(HeapObject* host, MaybeObject* target) override {
3966     DCHECK_IMPLIES(
3967         target->IsStrongOrWeakHeapObject() && Heap::InNewSpace(target),
3968         Heap::InToSpace(target));
3969     return target->IsStrongOrWeakHeapObject() && Heap::InNewSpace(target) &&
3970            !Heap::InNewSpace(host);
3971   }
3972 };
3973 
3974 template <RememberedSetType direction>
CollectSlots(MemoryChunk * chunk,Address start,Address end,std::set<Address> * untyped,std::set<std::pair<SlotType,Address>> * typed)3975 void CollectSlots(MemoryChunk* chunk, Address start, Address end,
3976                   std::set<Address>* untyped,
3977                   std::set<std::pair<SlotType, Address> >* typed) {
3978   RememberedSet<direction>::Iterate(chunk,
3979                                     [start, end, untyped](Address slot) {
3980                                       if (start <= slot && slot < end) {
3981                                         untyped->insert(slot);
3982                                       }
3983                                       return KEEP_SLOT;
3984                                     },
3985                                     SlotSet::PREFREE_EMPTY_BUCKETS);
3986   RememberedSet<direction>::IterateTyped(
3987       chunk, [start, end, typed](SlotType type, Address host, Address slot) {
3988         if (start <= slot && slot < end) {
3989           typed->insert(std::make_pair(type, slot));
3990         }
3991         return KEEP_SLOT;
3992       });
3993 }
3994 
VerifyRememberedSetFor(HeapObject * object)3995 void Heap::VerifyRememberedSetFor(HeapObject* object) {
3996   MemoryChunk* chunk = MemoryChunk::FromAddress(object->address());
3997   DCHECK_IMPLIES(chunk->mutex() == nullptr, InReadOnlySpace(object));
3998   // In RO_SPACE chunk->mutex() may be nullptr, so just ignore it.
3999   base::LockGuard<base::Mutex, base::NullBehavior::kIgnoreIfNull> lock_guard(
4000       chunk->mutex());
4001   Address start = object->address();
4002   Address end = start + object->Size();
4003   std::set<Address> old_to_new;
4004   std::set<std::pair<SlotType, Address> > typed_old_to_new;
4005   if (!InNewSpace(object)) {
4006     store_buffer()->MoveAllEntriesToRememberedSet();
4007     CollectSlots<OLD_TO_NEW>(chunk, start, end, &old_to_new, &typed_old_to_new);
4008     OldToNewSlotVerifyingVisitor visitor(&old_to_new, &typed_old_to_new);
4009     object->IterateBody(&visitor);
4010   }
4011   // TODO(ulan): Add old to old slot set verification once all weak objects
4012   // have their own instance types and slots are recorded for all weal fields.
4013 }
4014 #endif
4015 
4016 #ifdef DEBUG
VerifyCountersAfterSweeping()4017 void Heap::VerifyCountersAfterSweeping() {
4018   PagedSpaces spaces(this);
4019   for (PagedSpace* space = spaces.next(); space != nullptr;
4020        space = spaces.next()) {
4021     space->VerifyCountersAfterSweeping();
4022   }
4023 }
4024 
VerifyCountersBeforeConcurrentSweeping()4025 void Heap::VerifyCountersBeforeConcurrentSweeping() {
4026   PagedSpaces spaces(this);
4027   for (PagedSpace* space = spaces.next(); space != nullptr;
4028        space = spaces.next()) {
4029     space->VerifyCountersBeforeConcurrentSweeping();
4030   }
4031 }
4032 #endif
4033 
ZapFromSpace()4034 void Heap::ZapFromSpace() {
4035   if (!new_space_->IsFromSpaceCommitted()) return;
4036   for (Page* page : PageRange(new_space_->from_space().first_page(), nullptr)) {
4037     memory_allocator()->ZapBlock(page->area_start(),
4038                                  page->HighWaterMark() - page->area_start(),
4039                                  ZapValue());
4040   }
4041 }
4042 
ZapCodeObject(Address start_address,int size_in_bytes)4043 void Heap::ZapCodeObject(Address start_address, int size_in_bytes) {
4044 #ifdef DEBUG
4045   for (int i = 0; i < size_in_bytes / kPointerSize; i++) {
4046     reinterpret_cast<Object**>(start_address)[i] = Smi::FromInt(kCodeZapValue);
4047   }
4048 #endif
4049 }
4050 
builtin(int index)4051 Code* Heap::builtin(int index) {
4052   DCHECK(Builtins::IsBuiltinId(index));
4053   // Code::cast cannot be used here since we access builtins
4054   // during the marking phase of mark sweep. See IC::Clear.
4055   return reinterpret_cast<Code*>(builtins_[index]);
4056 }
4057 
builtin_address(int index)4058 Address Heap::builtin_address(int index) {
4059   DCHECK(Builtins::IsBuiltinId(index) || index == Builtins::builtin_count);
4060   return reinterpret_cast<Address>(&builtins_[index]);
4061 }
4062 
set_builtin(int index,HeapObject * builtin)4063 void Heap::set_builtin(int index, HeapObject* builtin) {
4064   DCHECK(Builtins::IsBuiltinId(index));
4065   DCHECK(Internals::HasHeapObjectTag(builtin));
4066   // The given builtin may be completely uninitialized thus we cannot check its
4067   // type here.
4068   builtins_[index] = builtin;
4069 }
4070 
IterateRoots(RootVisitor * v,VisitMode mode)4071 void Heap::IterateRoots(RootVisitor* v, VisitMode mode) {
4072   IterateStrongRoots(v, mode);
4073   IterateWeakRoots(v, mode);
4074 }
4075 
IterateWeakRoots(RootVisitor * v,VisitMode mode)4076 void Heap::IterateWeakRoots(RootVisitor* v, VisitMode mode) {
4077   const bool isMinorGC = mode == VISIT_ALL_IN_SCAVENGE ||
4078                          mode == VISIT_ALL_IN_MINOR_MC_MARK ||
4079                          mode == VISIT_ALL_IN_MINOR_MC_UPDATE;
4080   v->VisitRootPointer(
4081       Root::kStringTable, nullptr,
4082       reinterpret_cast<Object**>(&roots_[kStringTableRootIndex]));
4083   v->Synchronize(VisitorSynchronization::kStringTable);
4084   if (!isMinorGC && mode != VISIT_ALL_IN_SWEEP_NEWSPACE &&
4085       mode != VISIT_FOR_SERIALIZATION) {
4086     // Scavenge collections have special processing for this.
4087     // Do not visit for serialization, since the external string table will
4088     // be populated from scratch upon deserialization.
4089     external_string_table_.IterateAll(v);
4090   }
4091   v->Synchronize(VisitorSynchronization::kExternalStringsTable);
4092 }
4093 
IterateSmiRoots(RootVisitor * v)4094 void Heap::IterateSmiRoots(RootVisitor* v) {
4095   // Acquire execution access since we are going to read stack limit values.
4096   ExecutionAccess access(isolate());
4097   v->VisitRootPointers(Root::kSmiRootList, nullptr, &roots_[kSmiRootsStart],
4098                        &roots_[kRootListLength]);
4099   v->Synchronize(VisitorSynchronization::kSmiRootList);
4100 }
4101 
4102 // We cannot avoid stale handles to left-trimmed objects, but can only make
4103 // sure all handles still needed are updated. Filter out a stale pointer
4104 // and clear the slot to allow post processing of handles (needed because
4105 // the sweeper might actually free the underlying page).
4106 class FixStaleLeftTrimmedHandlesVisitor : public RootVisitor {
4107  public:
FixStaleLeftTrimmedHandlesVisitor(Heap * heap)4108   explicit FixStaleLeftTrimmedHandlesVisitor(Heap* heap) : heap_(heap) {
4109     USE(heap_);
4110   }
4111 
VisitRootPointer(Root root,const char * description,Object ** p)4112   void VisitRootPointer(Root root, const char* description,
4113                         Object** p) override {
4114     FixHandle(p);
4115   }
4116 
VisitRootPointers(Root root,const char * description,Object ** start,Object ** end)4117   void VisitRootPointers(Root root, const char* description, Object** start,
4118                          Object** end) override {
4119     for (Object** p = start; p < end; p++) FixHandle(p);
4120   }
4121 
4122  private:
FixHandle(Object ** p)4123   inline void FixHandle(Object** p) {
4124     if (!(*p)->IsHeapObject()) return;
4125     HeapObject* current = reinterpret_cast<HeapObject*>(*p);
4126     const MapWord map_word = current->map_word();
4127     if (!map_word.IsForwardingAddress() && current->IsFiller()) {
4128 #ifdef DEBUG
4129       // We need to find a FixedArrayBase map after walking the fillers.
4130       while (current->IsFiller()) {
4131         Address next = reinterpret_cast<Address>(current);
4132         if (current->map() == ReadOnlyRoots(heap_).one_pointer_filler_map()) {
4133           next += kPointerSize;
4134         } else if (current->map() ==
4135                    ReadOnlyRoots(heap_).two_pointer_filler_map()) {
4136           next += 2 * kPointerSize;
4137         } else {
4138           next += current->Size();
4139         }
4140         current = reinterpret_cast<HeapObject*>(next);
4141       }
4142       DCHECK(current->IsFixedArrayBase());
4143 #endif  // DEBUG
4144       *p = nullptr;
4145     }
4146   }
4147 
4148   Heap* heap_;
4149 };
4150 
IterateStrongRoots(RootVisitor * v,VisitMode mode)4151 void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
4152   const bool isMinorGC = mode == VISIT_ALL_IN_SCAVENGE ||
4153                          mode == VISIT_ALL_IN_MINOR_MC_MARK ||
4154                          mode == VISIT_ALL_IN_MINOR_MC_UPDATE;
4155   v->VisitRootPointers(Root::kStrongRootList, nullptr, &roots_[0],
4156                        &roots_[kStrongRootListLength]);
4157   v->Synchronize(VisitorSynchronization::kStrongRootList);
4158 
4159   isolate_->bootstrapper()->Iterate(v);
4160   v->Synchronize(VisitorSynchronization::kBootstrapper);
4161   isolate_->Iterate(v);
4162   v->Synchronize(VisitorSynchronization::kTop);
4163   Relocatable::Iterate(isolate_, v);
4164   v->Synchronize(VisitorSynchronization::kRelocatable);
4165   isolate_->debug()->Iterate(v);
4166   v->Synchronize(VisitorSynchronization::kDebug);
4167 
4168   isolate_->compilation_cache()->Iterate(v);
4169   v->Synchronize(VisitorSynchronization::kCompilationCache);
4170 
4171   // Iterate over local handles in handle scopes.
4172   FixStaleLeftTrimmedHandlesVisitor left_trim_visitor(this);
4173   isolate_->handle_scope_implementer()->Iterate(&left_trim_visitor);
4174   isolate_->handle_scope_implementer()->Iterate(v);
4175   isolate_->IterateDeferredHandles(v);
4176   v->Synchronize(VisitorSynchronization::kHandleScope);
4177 
4178   // Iterate over the builtin code objects and code stubs in the
4179   // heap. Note that it is not necessary to iterate over code objects
4180   // on scavenge collections.
4181   if (!isMinorGC) {
4182     IterateBuiltins(v);
4183     v->Synchronize(VisitorSynchronization::kBuiltins);
4184     isolate_->interpreter()->IterateDispatchTable(v);
4185     v->Synchronize(VisitorSynchronization::kDispatchTable);
4186   }
4187 
4188   // Iterate over global handles.
4189   switch (mode) {
4190     case VISIT_FOR_SERIALIZATION:
4191       // Global handles are not iterated by the serializer. Values referenced by
4192       // global handles need to be added manually.
4193       break;
4194     case VISIT_ONLY_STRONG:
4195       isolate_->global_handles()->IterateStrongRoots(v);
4196       break;
4197     case VISIT_ALL_IN_SCAVENGE:
4198       isolate_->global_handles()->IterateNewSpaceStrongAndDependentRoots(v);
4199       break;
4200     case VISIT_ALL_IN_MINOR_MC_MARK:
4201       // Global handles are processed manually be the minor MC.
4202       break;
4203     case VISIT_ALL_IN_MINOR_MC_UPDATE:
4204       // Global handles are processed manually be the minor MC.
4205       break;
4206     case VISIT_ALL_IN_SWEEP_NEWSPACE:
4207     case VISIT_ALL:
4208       isolate_->global_handles()->IterateAllRoots(v);
4209       break;
4210   }
4211   v->Synchronize(VisitorSynchronization::kGlobalHandles);
4212 
4213   // Iterate over eternal handles. Eternal handles are not iterated by the
4214   // serializer. Values referenced by eternal handles need to be added manually.
4215   if (mode != VISIT_FOR_SERIALIZATION) {
4216     if (isMinorGC) {
4217       isolate_->eternal_handles()->IterateNewSpaceRoots(v);
4218     } else {
4219       isolate_->eternal_handles()->IterateAllRoots(v);
4220     }
4221   }
4222   v->Synchronize(VisitorSynchronization::kEternalHandles);
4223 
4224   // Iterate over pointers being held by inactive threads.
4225   isolate_->thread_manager()->Iterate(v);
4226   v->Synchronize(VisitorSynchronization::kThreadManager);
4227 
4228   // Iterate over other strong roots (currently only identity maps).
4229   for (StrongRootsList* list = strong_roots_list_; list; list = list->next) {
4230     v->VisitRootPointers(Root::kStrongRoots, nullptr, list->start, list->end);
4231   }
4232   v->Synchronize(VisitorSynchronization::kStrongRoots);
4233 
4234   // Iterate over the partial snapshot cache unless serializing.
4235   if (mode != VISIT_FOR_SERIALIZATION) {
4236     SerializerDeserializer::Iterate(isolate_, v);
4237     // We don't do a v->Synchronize call here because the serializer and the
4238     // deserializer are deliberately out of sync here.
4239   }
4240 }
4241 
IterateWeakGlobalHandles(RootVisitor * v)4242 void Heap::IterateWeakGlobalHandles(RootVisitor* v) {
4243   isolate_->global_handles()->IterateWeakRoots(v);
4244 }
4245 
IterateBuiltins(RootVisitor * v)4246 void Heap::IterateBuiltins(RootVisitor* v) {
4247   for (int i = 0; i < Builtins::builtin_count; i++) {
4248     v->VisitRootPointer(Root::kBuiltins, Builtins::name(i), &builtins_[i]);
4249   }
4250 }
4251 
4252 // TODO(1236194): Since the heap size is configurable on the command line
4253 // and through the API, we should gracefully handle the case that the heap
4254 // size is not big enough to fit all the initial objects.
ConfigureHeap(size_t max_semi_space_size_in_kb,size_t max_old_generation_size_in_mb,size_t code_range_size_in_mb)4255 void Heap::ConfigureHeap(size_t max_semi_space_size_in_kb,
4256                          size_t max_old_generation_size_in_mb,
4257                          size_t code_range_size_in_mb) {
4258   // Overwrite default configuration.
4259   if (max_semi_space_size_in_kb != 0) {
4260     max_semi_space_size_ =
4261         RoundUp<Page::kPageSize>(max_semi_space_size_in_kb * KB);
4262   }
4263   if (max_old_generation_size_in_mb != 0) {
4264     max_old_generation_size_ = max_old_generation_size_in_mb * MB;
4265   }
4266 
4267   // If max space size flags are specified overwrite the configuration.
4268   if (FLAG_max_semi_space_size > 0) {
4269     max_semi_space_size_ = static_cast<size_t>(FLAG_max_semi_space_size) * MB;
4270   }
4271   if (FLAG_max_old_space_size > 0) {
4272     max_old_generation_size_ =
4273         static_cast<size_t>(FLAG_max_old_space_size) * MB;
4274   }
4275 
4276   if (Page::kPageSize > MB) {
4277     max_semi_space_size_ = RoundUp<Page::kPageSize>(max_semi_space_size_);
4278     max_old_generation_size_ =
4279         RoundUp<Page::kPageSize>(max_old_generation_size_);
4280   }
4281 
4282   if (FLAG_stress_compaction) {
4283     // This will cause more frequent GCs when stressing.
4284     max_semi_space_size_ = MB;
4285   }
4286 
4287   // The new space size must be a power of two to support single-bit testing
4288   // for containment.
4289   max_semi_space_size_ = static_cast<size_t>(base::bits::RoundUpToPowerOfTwo64(
4290       static_cast<uint64_t>(max_semi_space_size_)));
4291 
4292   if (max_semi_space_size_ == kMaxSemiSpaceSizeInKB * KB) {
4293     // Start with at least 1*MB semi-space on machines with a lot of memory.
4294     initial_semispace_size_ =
4295         Max(initial_semispace_size_, static_cast<size_t>(1 * MB));
4296   }
4297 
4298   if (FLAG_min_semi_space_size > 0) {
4299     size_t initial_semispace_size =
4300         static_cast<size_t>(FLAG_min_semi_space_size) * MB;
4301     if (initial_semispace_size > max_semi_space_size_) {
4302       initial_semispace_size_ = max_semi_space_size_;
4303       if (FLAG_trace_gc) {
4304         PrintIsolate(isolate_,
4305                      "Min semi-space size cannot be more than the maximum "
4306                      "semi-space size of %" PRIuS " MB\n",
4307                      max_semi_space_size_ / MB);
4308       }
4309     } else {
4310       initial_semispace_size_ =
4311           RoundUp<Page::kPageSize>(initial_semispace_size);
4312     }
4313   }
4314 
4315   initial_semispace_size_ = Min(initial_semispace_size_, max_semi_space_size_);
4316 
4317   if (FLAG_semi_space_growth_factor < 2) {
4318     FLAG_semi_space_growth_factor = 2;
4319   }
4320 
4321   // The old generation is paged and needs at least one page for each space.
4322   int paged_space_count =
4323       LAST_GROWABLE_PAGED_SPACE - FIRST_GROWABLE_PAGED_SPACE + 1;
4324   initial_max_old_generation_size_ = max_old_generation_size_ =
4325       Max(static_cast<size_t>(paged_space_count * Page::kPageSize),
4326           max_old_generation_size_);
4327 
4328   if (FLAG_initial_old_space_size > 0) {
4329     initial_old_generation_size_ = FLAG_initial_old_space_size * MB;
4330   } else {
4331     initial_old_generation_size_ =
4332         max_old_generation_size_ / kInitalOldGenerationLimitFactor;
4333   }
4334   old_generation_allocation_limit_ = initial_old_generation_size_;
4335 
4336   // We rely on being able to allocate new arrays in paged spaces.
4337   DCHECK(kMaxRegularHeapObjectSize >=
4338          (JSArray::kSize +
4339           FixedArray::SizeFor(JSArray::kInitialMaxFastElementArray) +
4340           AllocationMemento::kSize));
4341 
4342   code_range_size_ = code_range_size_in_mb * MB;
4343 
4344   configured_ = true;
4345 }
4346 
4347 
AddToRingBuffer(const char * string)4348 void Heap::AddToRingBuffer(const char* string) {
4349   size_t first_part =
4350       Min(strlen(string), kTraceRingBufferSize - ring_buffer_end_);
4351   memcpy(trace_ring_buffer_ + ring_buffer_end_, string, first_part);
4352   ring_buffer_end_ += first_part;
4353   if (first_part < strlen(string)) {
4354     ring_buffer_full_ = true;
4355     size_t second_part = strlen(string) - first_part;
4356     memcpy(trace_ring_buffer_, string + first_part, second_part);
4357     ring_buffer_end_ = second_part;
4358   }
4359 }
4360 
4361 
GetFromRingBuffer(char * buffer)4362 void Heap::GetFromRingBuffer(char* buffer) {
4363   size_t copied = 0;
4364   if (ring_buffer_full_) {
4365     copied = kTraceRingBufferSize - ring_buffer_end_;
4366     memcpy(buffer, trace_ring_buffer_ + ring_buffer_end_, copied);
4367   }
4368   memcpy(buffer + copied, trace_ring_buffer_, ring_buffer_end_);
4369 }
4370 
ConfigureHeapDefault()4371 void Heap::ConfigureHeapDefault() { ConfigureHeap(0, 0, 0); }
4372 
RecordStats(HeapStats * stats,bool take_snapshot)4373 void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
4374   *stats->start_marker = HeapStats::kStartMarker;
4375   *stats->end_marker = HeapStats::kEndMarker;
4376   *stats->ro_space_size = read_only_space_->Size();
4377   *stats->ro_space_capacity = read_only_space_->Capacity();
4378   *stats->new_space_size = new_space_->Size();
4379   *stats->new_space_capacity = new_space_->Capacity();
4380   *stats->old_space_size = old_space_->SizeOfObjects();
4381   *stats->old_space_capacity = old_space_->Capacity();
4382   *stats->code_space_size = code_space_->SizeOfObjects();
4383   *stats->code_space_capacity = code_space_->Capacity();
4384   *stats->map_space_size = map_space_->SizeOfObjects();
4385   *stats->map_space_capacity = map_space_->Capacity();
4386   *stats->lo_space_size = lo_space_->Size();
4387   isolate_->global_handles()->RecordStats(stats);
4388   *stats->memory_allocator_size = memory_allocator()->Size();
4389   *stats->memory_allocator_capacity =
4390       memory_allocator()->Size() + memory_allocator()->Available();
4391   *stats->os_error = base::OS::GetLastError();
4392   *stats->malloced_memory = isolate_->allocator()->GetCurrentMemoryUsage();
4393   *stats->malloced_peak_memory = isolate_->allocator()->GetMaxMemoryUsage();
4394   if (take_snapshot) {
4395     HeapIterator iterator(this);
4396     for (HeapObject* obj = iterator.next(); obj != nullptr;
4397          obj = iterator.next()) {
4398       InstanceType type = obj->map()->instance_type();
4399       DCHECK(0 <= type && type <= LAST_TYPE);
4400       stats->objects_per_type[type]++;
4401       stats->size_per_type[type] += obj->Size();
4402     }
4403   }
4404   if (stats->last_few_messages != nullptr)
4405     GetFromRingBuffer(stats->last_few_messages);
4406   if (stats->js_stacktrace != nullptr) {
4407     FixedStringAllocator fixed(stats->js_stacktrace, kStacktraceBufferSize - 1);
4408     StringStream accumulator(&fixed, StringStream::kPrintObjectConcise);
4409     if (gc_state() == Heap::NOT_IN_GC) {
4410       isolate()->PrintStack(&accumulator, Isolate::kPrintStackVerbose);
4411     } else {
4412       accumulator.Add("Cannot get stack trace in GC.");
4413     }
4414   }
4415 }
4416 
OldGenerationSizeOfObjects()4417 size_t Heap::OldGenerationSizeOfObjects() {
4418   PagedSpaces spaces(this, PagedSpaces::SpacesSpecifier::kAllPagedSpaces);
4419   size_t total = 0;
4420   for (PagedSpace* space = spaces.next(); space != nullptr;
4421        space = spaces.next()) {
4422     total += space->SizeOfObjects();
4423   }
4424   return total + lo_space_->SizeOfObjects();
4425 }
4426 
PromotedExternalMemorySize()4427 uint64_t Heap::PromotedExternalMemorySize() {
4428   if (external_memory_ <= external_memory_at_last_mark_compact_) return 0;
4429   return static_cast<uint64_t>(external_memory_ -
4430                                external_memory_at_last_mark_compact_);
4431 }
4432 
ShouldOptimizeForLoadTime()4433 bool Heap::ShouldOptimizeForLoadTime() {
4434   return isolate()->rail_mode() == PERFORMANCE_LOAD &&
4435          !AllocationLimitOvershotByLargeMargin() &&
4436          MonotonicallyIncreasingTimeInMs() <
4437              isolate()->LoadStartTimeMs() + kMaxLoadTimeMs;
4438 }
4439 
4440 // This predicate is called when an old generation space cannot allocated from
4441 // the free list and is about to add a new page. Returning false will cause a
4442 // major GC. It happens when the old generation allocation limit is reached and
4443 // - either we need to optimize for memory usage,
4444 // - or the incremental marking is not in progress and we cannot start it.
ShouldExpandOldGenerationOnSlowAllocation()4445 bool Heap::ShouldExpandOldGenerationOnSlowAllocation() {
4446   if (always_allocate() || OldGenerationSpaceAvailable() > 0) return true;
4447   // We reached the old generation allocation limit.
4448 
4449   if (ShouldOptimizeForMemoryUsage()) return false;
4450 
4451   if (ShouldOptimizeForLoadTime()) return true;
4452 
4453   if (incremental_marking()->NeedsFinalization()) {
4454     return !AllocationLimitOvershotByLargeMargin();
4455   }
4456 
4457   if (incremental_marking()->IsStopped() &&
4458       IncrementalMarkingLimitReached() == IncrementalMarkingLimit::kNoLimit) {
4459     // We cannot start incremental marking.
4460     return false;
4461   }
4462   return true;
4463 }
4464 
CurrentHeapGrowingMode()4465 Heap::HeapGrowingMode Heap::CurrentHeapGrowingMode() {
4466   if (ShouldReduceMemory() || FLAG_stress_compaction) {
4467     return Heap::HeapGrowingMode::kMinimal;
4468   }
4469 
4470   if (ShouldOptimizeForMemoryUsage()) {
4471     return Heap::HeapGrowingMode::kConservative;
4472   }
4473 
4474   if (memory_reducer()->ShouldGrowHeapSlowly()) {
4475     return Heap::HeapGrowingMode::kSlow;
4476   }
4477 
4478   return Heap::HeapGrowingMode::kDefault;
4479 }
4480 
4481 // This function returns either kNoLimit, kSoftLimit, or kHardLimit.
4482 // The kNoLimit means that either incremental marking is disabled or it is too
4483 // early to start incremental marking.
4484 // The kSoftLimit means that incremental marking should be started soon.
4485 // The kHardLimit means that incremental marking should be started immediately.
IncrementalMarkingLimitReached()4486 Heap::IncrementalMarkingLimit Heap::IncrementalMarkingLimitReached() {
4487   // Code using an AlwaysAllocateScope assumes that the GC state does not
4488   // change; that implies that no marking steps must be performed.
4489   if (!incremental_marking()->CanBeActivated() || always_allocate()) {
4490     // Incremental marking is disabled or it is too early to start.
4491     return IncrementalMarkingLimit::kNoLimit;
4492   }
4493   if (FLAG_stress_incremental_marking) {
4494     return IncrementalMarkingLimit::kHardLimit;
4495   }
4496   if (OldGenerationSizeOfObjects() <=
4497       IncrementalMarking::kActivationThreshold) {
4498     // Incremental marking is disabled or it is too early to start.
4499     return IncrementalMarkingLimit::kNoLimit;
4500   }
4501   if ((FLAG_stress_compaction && (gc_count_ & 1) != 0) ||
4502       HighMemoryPressure()) {
4503     // If there is high memory pressure or stress testing is enabled, then
4504     // start marking immediately.
4505     return IncrementalMarkingLimit::kHardLimit;
4506   }
4507 
4508   if (FLAG_stress_marking > 0) {
4509     double gained_since_last_gc =
4510         PromotedSinceLastGC() +
4511         (external_memory_ - external_memory_at_last_mark_compact_);
4512     double size_before_gc =
4513         OldGenerationObjectsAndPromotedExternalMemorySize() -
4514         gained_since_last_gc;
4515     double bytes_to_limit = old_generation_allocation_limit_ - size_before_gc;
4516     if (bytes_to_limit > 0) {
4517       double current_percent = (gained_since_last_gc / bytes_to_limit) * 100.0;
4518 
4519       if (FLAG_trace_stress_marking) {
4520         isolate()->PrintWithTimestamp(
4521             "[IncrementalMarking] %.2lf%% of the memory limit reached\n",
4522             current_percent);
4523       }
4524 
4525       if (FLAG_fuzzer_gc_analysis) {
4526         // Skips values >=100% since they already trigger marking.
4527         if (current_percent < 100.0) {
4528           max_marking_limit_reached_ =
4529               std::max(max_marking_limit_reached_, current_percent);
4530         }
4531       } else if (static_cast<int>(current_percent) >=
4532                  stress_marking_percentage_) {
4533         stress_marking_percentage_ = NextStressMarkingLimit();
4534         return IncrementalMarkingLimit::kHardLimit;
4535       }
4536     }
4537   }
4538 
4539   size_t old_generation_space_available = OldGenerationSpaceAvailable();
4540 
4541   if (old_generation_space_available > new_space_->Capacity()) {
4542     return IncrementalMarkingLimit::kNoLimit;
4543   }
4544   if (ShouldOptimizeForMemoryUsage()) {
4545     return IncrementalMarkingLimit::kHardLimit;
4546   }
4547   if (ShouldOptimizeForLoadTime()) {
4548     return IncrementalMarkingLimit::kNoLimit;
4549   }
4550   if (old_generation_space_available == 0) {
4551     return IncrementalMarkingLimit::kHardLimit;
4552   }
4553   return IncrementalMarkingLimit::kSoftLimit;
4554 }
4555 
EnableInlineAllocation()4556 void Heap::EnableInlineAllocation() {
4557   if (!inline_allocation_disabled_) return;
4558   inline_allocation_disabled_ = false;
4559 
4560   // Update inline allocation limit for new space.
4561   new_space()->UpdateInlineAllocationLimit(0);
4562 }
4563 
4564 
DisableInlineAllocation()4565 void Heap::DisableInlineAllocation() {
4566   if (inline_allocation_disabled_) return;
4567   inline_allocation_disabled_ = true;
4568 
4569   // Update inline allocation limit for new space.
4570   new_space()->UpdateInlineAllocationLimit(0);
4571 
4572   // Update inline allocation limit for old spaces.
4573   PagedSpaces spaces(this);
4574   CodeSpaceMemoryModificationScope modification_scope(this);
4575   for (PagedSpace* space = spaces.next(); space != nullptr;
4576        space = spaces.next()) {
4577     space->FreeLinearAllocationArea();
4578   }
4579 }
4580 
EnsureImmovableCode(HeapObject * heap_object,int object_size)4581 HeapObject* Heap::EnsureImmovableCode(HeapObject* heap_object,
4582                                       int object_size) {
4583   // Code objects which should stay at a fixed address are allocated either
4584   // in the first page of code space, in large object space, or (during
4585   // snapshot creation) the containing page is marked as immovable.
4586   DCHECK(heap_object);
4587   DCHECK(code_space_->Contains(heap_object));
4588   DCHECK_GE(object_size, 0);
4589   if (!Heap::IsImmovable(heap_object)) {
4590     if (isolate()->serializer_enabled() ||
4591         code_space_->first_page()->Contains(heap_object->address())) {
4592       MemoryChunk::FromAddress(heap_object->address())->MarkNeverEvacuate();
4593     } else {
4594       // Discard the first code allocation, which was on a page where it could
4595       // be moved.
4596       CreateFillerObjectAt(heap_object->address(), object_size,
4597                            ClearRecordedSlots::kNo);
4598       heap_object = AllocateRawCodeInLargeObjectSpace(object_size);
4599       UnprotectAndRegisterMemoryChunk(heap_object);
4600       ZapCodeObject(heap_object->address(), object_size);
4601       OnAllocationEvent(heap_object, object_size);
4602     }
4603   }
4604   return heap_object;
4605 }
4606 
AllocateRawWithLightRetry(int size,AllocationSpace space,AllocationAlignment alignment)4607 HeapObject* Heap::AllocateRawWithLightRetry(int size, AllocationSpace space,
4608                                             AllocationAlignment alignment) {
4609   HeapObject* result;
4610   AllocationResult alloc = AllocateRaw(size, space, alignment);
4611   if (alloc.To(&result)) {
4612     DCHECK(result != ReadOnlyRoots(this).exception());
4613     return result;
4614   }
4615   // Two GCs before panicking. In newspace will almost always succeed.
4616   for (int i = 0; i < 2; i++) {
4617     CollectGarbage(alloc.RetrySpace(),
4618                    GarbageCollectionReason::kAllocationFailure);
4619     alloc = AllocateRaw(size, space, alignment);
4620     if (alloc.To(&result)) {
4621       DCHECK(result != ReadOnlyRoots(this).exception());
4622       return result;
4623     }
4624   }
4625   return nullptr;
4626 }
4627 
AllocateRawWithRetryOrFail(int size,AllocationSpace space,AllocationAlignment alignment)4628 HeapObject* Heap::AllocateRawWithRetryOrFail(int size, AllocationSpace space,
4629                                              AllocationAlignment alignment) {
4630   AllocationResult alloc;
4631   HeapObject* result = AllocateRawWithLightRetry(size, space, alignment);
4632   if (result) return result;
4633 
4634   isolate()->counters()->gc_last_resort_from_handles()->Increment();
4635   CollectAllAvailableGarbage(GarbageCollectionReason::kLastResort);
4636   {
4637     AlwaysAllocateScope scope(isolate());
4638     alloc = AllocateRaw(size, space, alignment);
4639   }
4640   if (alloc.To(&result)) {
4641     DCHECK(result != ReadOnlyRoots(this).exception());
4642     return result;
4643   }
4644   // TODO(1181417): Fix this.
4645   FatalProcessOutOfMemory("CALL_AND_RETRY_LAST");
4646   return nullptr;
4647 }
4648 
4649 // TODO(jkummerow): Refactor this. AllocateRaw should take an "immovability"
4650 // parameter and just do what's necessary.
AllocateRawCodeInLargeObjectSpace(int size)4651 HeapObject* Heap::AllocateRawCodeInLargeObjectSpace(int size) {
4652   AllocationResult alloc = lo_space()->AllocateRaw(size, EXECUTABLE);
4653   HeapObject* result;
4654   if (alloc.To(&result)) {
4655     DCHECK(result != ReadOnlyRoots(this).exception());
4656     return result;
4657   }
4658   // Two GCs before panicking.
4659   for (int i = 0; i < 2; i++) {
4660     CollectGarbage(alloc.RetrySpace(),
4661                    GarbageCollectionReason::kAllocationFailure);
4662     alloc = lo_space()->AllocateRaw(size, EXECUTABLE);
4663     if (alloc.To(&result)) {
4664       DCHECK(result != ReadOnlyRoots(this).exception());
4665       return result;
4666     }
4667   }
4668   isolate()->counters()->gc_last_resort_from_handles()->Increment();
4669   CollectAllAvailableGarbage(GarbageCollectionReason::kLastResort);
4670   {
4671     AlwaysAllocateScope scope(isolate());
4672     alloc = lo_space()->AllocateRaw(size, EXECUTABLE);
4673   }
4674   if (alloc.To(&result)) {
4675     DCHECK(result != ReadOnlyRoots(this).exception());
4676     return result;
4677   }
4678   // TODO(1181417): Fix this.
4679   FatalProcessOutOfMemory("CALL_AND_RETRY_LAST");
4680   return nullptr;
4681 }
4682 
SetUp()4683 void Heap::SetUp() {
4684 #ifdef V8_ENABLE_ALLOCATION_TIMEOUT
4685   allocation_timeout_ = NextAllocationTimeout();
4686 #endif
4687 
4688   // Initialize heap spaces and initial maps and objects.
4689   //
4690   // If the heap is not yet configured (e.g. through the API), configure it.
4691   // Configuration is based on the flags new-space-size (really the semispace
4692   // size) and old-space-size if set or the initial values of semispace_size_
4693   // and old_generation_size_ otherwise.
4694   if (!configured_) ConfigureHeapDefault();
4695 
4696   mmap_region_base_ =
4697       reinterpret_cast<uintptr_t>(v8::internal::GetRandomMmapAddr()) &
4698       ~kMmapRegionMask;
4699 
4700   // Set up memory allocator.
4701   memory_allocator_ =
4702       new MemoryAllocator(isolate_, MaxReserved(), code_range_size_);
4703 
4704   store_buffer_ = new StoreBuffer(this);
4705 
4706   heap_controller_ = new HeapController(this);
4707 
4708   mark_compact_collector_ = new MarkCompactCollector(this);
4709   incremental_marking_ =
4710       new IncrementalMarking(this, mark_compact_collector_->marking_worklist(),
4711                              mark_compact_collector_->weak_objects());
4712 
4713   if (FLAG_concurrent_marking) {
4714     MarkCompactCollector::MarkingWorklist* marking_worklist =
4715         mark_compact_collector_->marking_worklist();
4716     concurrent_marking_ = new ConcurrentMarking(
4717         this, marking_worklist->shared(), marking_worklist->bailout(),
4718         marking_worklist->on_hold(), mark_compact_collector_->weak_objects());
4719   } else {
4720     concurrent_marking_ =
4721         new ConcurrentMarking(this, nullptr, nullptr, nullptr, nullptr);
4722   }
4723 
4724   for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
4725     space_[i] = nullptr;
4726   }
4727 
4728   space_[RO_SPACE] = read_only_space_ = new ReadOnlySpace(this);
4729   space_[NEW_SPACE] = new_space_ =
4730       new NewSpace(this, initial_semispace_size_, max_semi_space_size_);
4731   space_[OLD_SPACE] = old_space_ = new OldSpace(this);
4732   space_[CODE_SPACE] = code_space_ = new CodeSpace(this);
4733   space_[MAP_SPACE] = map_space_ = new MapSpace(this);
4734   space_[LO_SPACE] = lo_space_ = new LargeObjectSpace(this);
4735   space_[NEW_LO_SPACE] = new_lo_space_ = new NewLargeObjectSpace(this);
4736 
4737   for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount);
4738        i++) {
4739     deferred_counters_[i] = 0;
4740   }
4741 
4742   tracer_ = new GCTracer(this);
4743 #ifdef ENABLE_MINOR_MC
4744   minor_mark_compact_collector_ = new MinorMarkCompactCollector(this);
4745 #else
4746   minor_mark_compact_collector_ = nullptr;
4747 #endif  // ENABLE_MINOR_MC
4748   array_buffer_collector_ = new ArrayBufferCollector(this);
4749   gc_idle_time_handler_ = new GCIdleTimeHandler();
4750   memory_reducer_ = new MemoryReducer(this);
4751   if (V8_UNLIKELY(FLAG_gc_stats)) {
4752     live_object_stats_ = new ObjectStats(this);
4753     dead_object_stats_ = new ObjectStats(this);
4754   }
4755   scavenge_job_ = new ScavengeJob();
4756   local_embedder_heap_tracer_ = new LocalEmbedderHeapTracer(isolate());
4757 
4758   LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity()));
4759   LOG(isolate_, IntPtrTEvent("heap-available", Available()));
4760 
4761   store_buffer()->SetUp();
4762 
4763   mark_compact_collector()->SetUp();
4764 #ifdef ENABLE_MINOR_MC
4765   if (minor_mark_compact_collector() != nullptr) {
4766     minor_mark_compact_collector()->SetUp();
4767   }
4768 #endif  // ENABLE_MINOR_MC
4769 
4770   idle_scavenge_observer_ = new IdleScavengeObserver(
4771       *this, ScavengeJob::kBytesAllocatedBeforeNextIdleTask);
4772   new_space()->AddAllocationObserver(idle_scavenge_observer_);
4773 
4774   SetGetExternallyAllocatedMemoryInBytesCallback(
4775       DefaultGetExternallyAllocatedMemoryInBytesCallback);
4776 
4777   if (FLAG_stress_marking > 0) {
4778     stress_marking_percentage_ = NextStressMarkingLimit();
4779     stress_marking_observer_ = new StressMarkingObserver(*this);
4780     AddAllocationObserversToAllSpaces(stress_marking_observer_,
4781                                       stress_marking_observer_);
4782   }
4783   if (FLAG_stress_scavenge > 0) {
4784     stress_scavenge_observer_ = new StressScavengeObserver(*this);
4785     new_space()->AddAllocationObserver(stress_scavenge_observer_);
4786   }
4787 
4788   write_protect_code_memory_ = FLAG_write_protect_code_memory;
4789 
4790   external_reference_table_.Init(isolate_);
4791 }
4792 
InitializeHashSeed()4793 void Heap::InitializeHashSeed() {
4794   uint64_t new_hash_seed;
4795   if (FLAG_hash_seed == 0) {
4796     int64_t rnd = isolate()->random_number_generator()->NextInt64();
4797     new_hash_seed = static_cast<uint64_t>(rnd);
4798   } else {
4799     new_hash_seed = static_cast<uint64_t>(FLAG_hash_seed);
4800   }
4801   hash_seed()->copy_in(0, reinterpret_cast<byte*>(&new_hash_seed), kInt64Size);
4802 }
4803 
SetStackLimits()4804 void Heap::SetStackLimits() {
4805   DCHECK_NOT_NULL(isolate_);
4806   DCHECK(isolate_ == isolate());
4807   // On 64 bit machines, pointers are generally out of range of Smis.  We write
4808   // something that looks like an out of range Smi to the GC.
4809 
4810   // Set up the special root array entries containing the stack limits.
4811   // These are actually addresses, but the tag makes the GC ignore it.
4812   roots_[kStackLimitRootIndex] = reinterpret_cast<Object*>(
4813       (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag);
4814   roots_[kRealStackLimitRootIndex] = reinterpret_cast<Object*>(
4815       (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag);
4816 }
4817 
ClearStackLimits()4818 void Heap::ClearStackLimits() {
4819   roots_[kStackLimitRootIndex] = Smi::kZero;
4820   roots_[kRealStackLimitRootIndex] = Smi::kZero;
4821 }
4822 
NextAllocationTimeout(int current_timeout)4823 int Heap::NextAllocationTimeout(int current_timeout) {
4824   if (FLAG_random_gc_interval > 0) {
4825     // If current timeout hasn't reached 0 the GC was caused by something
4826     // different than --stress-atomic-gc flag and we don't update the timeout.
4827     if (current_timeout <= 0) {
4828       return isolate()->fuzzer_rng()->NextInt(FLAG_random_gc_interval + 1);
4829     } else {
4830       return current_timeout;
4831     }
4832   }
4833   return FLAG_gc_interval;
4834 }
4835 
PrintAllocationsHash()4836 void Heap::PrintAllocationsHash() {
4837   uint32_t hash = StringHasher::GetHashCore(raw_allocations_hash_);
4838   PrintF("\n### Allocations = %u, hash = 0x%08x\n", allocations_count(), hash);
4839 }
4840 
PrintMaxMarkingLimitReached()4841 void Heap::PrintMaxMarkingLimitReached() {
4842   PrintF("\n### Maximum marking limit reached = %.02lf\n",
4843          max_marking_limit_reached_);
4844 }
4845 
PrintMaxNewSpaceSizeReached()4846 void Heap::PrintMaxNewSpaceSizeReached() {
4847   PrintF("\n### Maximum new space size reached = %.02lf\n",
4848          stress_scavenge_observer_->MaxNewSpaceSizeReached());
4849 }
4850 
NextStressMarkingLimit()4851 int Heap::NextStressMarkingLimit() {
4852   return isolate()->fuzzer_rng()->NextInt(FLAG_stress_marking + 1);
4853 }
4854 
NotifyDeserializationComplete()4855 void Heap::NotifyDeserializationComplete() {
4856   PagedSpaces spaces(this);
4857   for (PagedSpace* s = spaces.next(); s != nullptr; s = spaces.next()) {
4858     if (isolate()->snapshot_available()) s->ShrinkImmortalImmovablePages();
4859 #ifdef DEBUG
4860     // All pages right after bootstrapping must be marked as never-evacuate.
4861     for (Page* p : *s) {
4862       DCHECK(p->NeverEvacuate());
4863     }
4864 #endif  // DEBUG
4865   }
4866 
4867   read_only_space()->MarkAsReadOnly();
4868   deserialization_complete_ = true;
4869 }
4870 
SetEmbedderHeapTracer(EmbedderHeapTracer * tracer)4871 void Heap::SetEmbedderHeapTracer(EmbedderHeapTracer* tracer) {
4872   DCHECK_EQ(gc_state_, HeapState::NOT_IN_GC);
4873   local_embedder_heap_tracer()->SetRemoteTracer(tracer);
4874 }
4875 
TracePossibleWrapper(JSObject * js_object)4876 void Heap::TracePossibleWrapper(JSObject* js_object) {
4877   DCHECK(js_object->IsApiWrapper());
4878   if (js_object->GetEmbedderFieldCount() >= 2 &&
4879       js_object->GetEmbedderField(0) &&
4880       js_object->GetEmbedderField(0) != ReadOnlyRoots(this).undefined_value() &&
4881       js_object->GetEmbedderField(1) != ReadOnlyRoots(this).undefined_value()) {
4882     DCHECK_EQ(0,
4883               reinterpret_cast<intptr_t>(js_object->GetEmbedderField(0)) % 2);
4884     local_embedder_heap_tracer()->AddWrapperToTrace(std::pair<void*, void*>(
4885         reinterpret_cast<void*>(js_object->GetEmbedderField(0)),
4886         reinterpret_cast<void*>(js_object->GetEmbedderField(1))));
4887   }
4888 }
4889 
RegisterExternallyReferencedObject(Object ** object)4890 void Heap::RegisterExternallyReferencedObject(Object** object) {
4891   // The embedder is not aware of whether numbers are materialized as heap
4892   // objects are just passed around as Smis.
4893   if (!(*object)->IsHeapObject()) return;
4894   HeapObject* heap_object = HeapObject::cast(*object);
4895   DCHECK(Contains(heap_object));
4896   if (FLAG_incremental_marking_wrappers && incremental_marking()->IsMarking()) {
4897     incremental_marking()->WhiteToGreyAndPush(heap_object);
4898   } else {
4899     DCHECK(mark_compact_collector()->in_use());
4900     mark_compact_collector()->MarkExternallyReferencedObject(heap_object);
4901   }
4902 }
4903 
StartTearDown()4904 void Heap::StartTearDown() { SetGCState(TEAR_DOWN); }
4905 
TearDown()4906 void Heap::TearDown() {
4907   DCHECK_EQ(gc_state_, TEAR_DOWN);
4908 #ifdef VERIFY_HEAP
4909   if (FLAG_verify_heap) {
4910     Verify();
4911   }
4912 #endif
4913 
4914   UpdateMaximumCommitted();
4915 
4916   if (FLAG_verify_predictable || FLAG_fuzzer_gc_analysis) {
4917     PrintAllocationsHash();
4918   }
4919 
4920   if (FLAG_fuzzer_gc_analysis) {
4921     if (FLAG_stress_marking > 0) {
4922       PrintMaxMarkingLimitReached();
4923     }
4924     if (FLAG_stress_scavenge > 0) {
4925       PrintMaxNewSpaceSizeReached();
4926     }
4927   }
4928 
4929   new_space()->RemoveAllocationObserver(idle_scavenge_observer_);
4930   delete idle_scavenge_observer_;
4931   idle_scavenge_observer_ = nullptr;
4932 
4933   if (FLAG_stress_marking > 0) {
4934     RemoveAllocationObserversFromAllSpaces(stress_marking_observer_,
4935                                            stress_marking_observer_);
4936     delete stress_marking_observer_;
4937     stress_marking_observer_ = nullptr;
4938   }
4939   if (FLAG_stress_scavenge > 0) {
4940     new_space()->RemoveAllocationObserver(stress_scavenge_observer_);
4941     delete stress_scavenge_observer_;
4942     stress_scavenge_observer_ = nullptr;
4943   }
4944 
4945   if (heap_controller_ != nullptr) {
4946     delete heap_controller_;
4947     heap_controller_ = nullptr;
4948   }
4949 
4950   if (mark_compact_collector_ != nullptr) {
4951     mark_compact_collector_->TearDown();
4952     delete mark_compact_collector_;
4953     mark_compact_collector_ = nullptr;
4954   }
4955 
4956 #ifdef ENABLE_MINOR_MC
4957   if (minor_mark_compact_collector_ != nullptr) {
4958     minor_mark_compact_collector_->TearDown();
4959     delete minor_mark_compact_collector_;
4960     minor_mark_compact_collector_ = nullptr;
4961   }
4962 #endif  // ENABLE_MINOR_MC
4963 
4964   if (array_buffer_collector_ != nullptr) {
4965     delete array_buffer_collector_;
4966     array_buffer_collector_ = nullptr;
4967   }
4968 
4969   delete incremental_marking_;
4970   incremental_marking_ = nullptr;
4971 
4972   delete concurrent_marking_;
4973   concurrent_marking_ = nullptr;
4974 
4975   delete gc_idle_time_handler_;
4976   gc_idle_time_handler_ = nullptr;
4977 
4978   if (memory_reducer_ != nullptr) {
4979     memory_reducer_->TearDown();
4980     delete memory_reducer_;
4981     memory_reducer_ = nullptr;
4982   }
4983 
4984   if (live_object_stats_ != nullptr) {
4985     delete live_object_stats_;
4986     live_object_stats_ = nullptr;
4987   }
4988 
4989   if (dead_object_stats_ != nullptr) {
4990     delete dead_object_stats_;
4991     dead_object_stats_ = nullptr;
4992   }
4993 
4994   delete local_embedder_heap_tracer_;
4995   local_embedder_heap_tracer_ = nullptr;
4996 
4997   delete scavenge_job_;
4998   scavenge_job_ = nullptr;
4999 
5000   isolate_->global_handles()->TearDown();
5001 
5002   external_string_table_.TearDown();
5003 
5004   // Tear down all ArrayBuffers before tearing down the heap since  their
5005   // byte_length may be a HeapNumber which is required for freeing the backing
5006   // store.
5007   ArrayBufferTracker::TearDown(this);
5008 
5009   delete tracer_;
5010   tracer_ = nullptr;
5011 
5012   for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
5013     delete space_[i];
5014     space_[i] = nullptr;
5015   }
5016 
5017   store_buffer()->TearDown();
5018 
5019   memory_allocator()->TearDown();
5020 
5021   StrongRootsList* next = nullptr;
5022   for (StrongRootsList* list = strong_roots_list_; list; list = next) {
5023     next = list->next;
5024     delete list;
5025   }
5026   strong_roots_list_ = nullptr;
5027 
5028   delete store_buffer_;
5029   store_buffer_ = nullptr;
5030 
5031   delete memory_allocator_;
5032   memory_allocator_ = nullptr;
5033 }
5034 
AddGCPrologueCallback(v8::Isolate::GCCallbackWithData callback,GCType gc_type,void * data)5035 void Heap::AddGCPrologueCallback(v8::Isolate::GCCallbackWithData callback,
5036                                  GCType gc_type, void* data) {
5037   DCHECK_NOT_NULL(callback);
5038   DCHECK(gc_prologue_callbacks_.end() ==
5039          std::find(gc_prologue_callbacks_.begin(), gc_prologue_callbacks_.end(),
5040                    GCCallbackTuple(callback, gc_type, data)));
5041   gc_prologue_callbacks_.emplace_back(callback, gc_type, data);
5042 }
5043 
RemoveGCPrologueCallback(v8::Isolate::GCCallbackWithData callback,void * data)5044 void Heap::RemoveGCPrologueCallback(v8::Isolate::GCCallbackWithData callback,
5045                                     void* data) {
5046   DCHECK_NOT_NULL(callback);
5047   for (size_t i = 0; i < gc_prologue_callbacks_.size(); i++) {
5048     if (gc_prologue_callbacks_[i].callback == callback &&
5049         gc_prologue_callbacks_[i].data == data) {
5050       gc_prologue_callbacks_[i] = gc_prologue_callbacks_.back();
5051       gc_prologue_callbacks_.pop_back();
5052       return;
5053     }
5054   }
5055   UNREACHABLE();
5056 }
5057 
AddGCEpilogueCallback(v8::Isolate::GCCallbackWithData callback,GCType gc_type,void * data)5058 void Heap::AddGCEpilogueCallback(v8::Isolate::GCCallbackWithData callback,
5059                                  GCType gc_type, void* data) {
5060   DCHECK_NOT_NULL(callback);
5061   DCHECK(gc_epilogue_callbacks_.end() ==
5062          std::find(gc_epilogue_callbacks_.begin(), gc_epilogue_callbacks_.end(),
5063                    GCCallbackTuple(callback, gc_type, data)));
5064   gc_epilogue_callbacks_.emplace_back(callback, gc_type, data);
5065 }
5066 
RemoveGCEpilogueCallback(v8::Isolate::GCCallbackWithData callback,void * data)5067 void Heap::RemoveGCEpilogueCallback(v8::Isolate::GCCallbackWithData callback,
5068                                     void* data) {
5069   DCHECK_NOT_NULL(callback);
5070   for (size_t i = 0; i < gc_epilogue_callbacks_.size(); i++) {
5071     if (gc_epilogue_callbacks_[i].callback == callback &&
5072         gc_epilogue_callbacks_[i].data == data) {
5073       gc_epilogue_callbacks_[i] = gc_epilogue_callbacks_.back();
5074       gc_epilogue_callbacks_.pop_back();
5075       return;
5076     }
5077   }
5078   UNREACHABLE();
5079 }
5080 
5081 namespace {
CompactWeakArrayList(Heap * heap,Handle<WeakArrayList> array,PretenureFlag pretenure)5082 Handle<WeakArrayList> CompactWeakArrayList(Heap* heap,
5083                                            Handle<WeakArrayList> array,
5084                                            PretenureFlag pretenure) {
5085   if (array->length() == 0) {
5086     return array;
5087   }
5088   int new_length = array->CountLiveWeakReferences();
5089   if (new_length == array->length()) {
5090     return array;
5091   }
5092 
5093   Handle<WeakArrayList> new_array = WeakArrayList::EnsureSpace(
5094       heap->isolate(),
5095       handle(ReadOnlyRoots(heap).empty_weak_array_list(), heap->isolate()),
5096       new_length, pretenure);
5097   // Allocation might have caused GC and turned some of the elements into
5098   // cleared weak heap objects. Count the number of live references again and
5099   // fill in the new array.
5100   int copy_to = 0;
5101   for (int i = 0; i < array->length(); i++) {
5102     MaybeObject* element = array->Get(i);
5103     if (element->IsClearedWeakHeapObject()) continue;
5104     new_array->Set(copy_to++, element);
5105   }
5106   new_array->set_length(copy_to);
5107   return new_array;
5108 }
5109 
5110 }  // anonymous namespace
5111 
CompactWeakArrayLists(PretenureFlag pretenure)5112 void Heap::CompactWeakArrayLists(PretenureFlag pretenure) {
5113   // Find known PrototypeUsers and compact them.
5114   std::vector<Handle<PrototypeInfo>> prototype_infos;
5115   {
5116     HeapIterator iterator(this);
5117     for (HeapObject* o = iterator.next(); o != nullptr; o = iterator.next()) {
5118       if (o->IsPrototypeInfo()) {
5119         PrototypeInfo* prototype_info = PrototypeInfo::cast(o);
5120         if (prototype_info->prototype_users()->IsWeakArrayList()) {
5121           prototype_infos.emplace_back(handle(prototype_info, isolate()));
5122         }
5123       }
5124     }
5125   }
5126   for (auto& prototype_info : prototype_infos) {
5127     Handle<WeakArrayList> array(
5128         WeakArrayList::cast(prototype_info->prototype_users()), isolate());
5129     DCHECK_IMPLIES(pretenure == TENURED,
5130                    InOldSpace(*array) ||
5131                        *array == ReadOnlyRoots(this).empty_weak_array_list());
5132     WeakArrayList* new_array = PrototypeUsers::Compact(
5133         array, this, JSObject::PrototypeRegistryCompactionCallback, pretenure);
5134     prototype_info->set_prototype_users(new_array);
5135   }
5136 
5137   // Find known WeakArrayLists and compact them.
5138   Handle<WeakArrayList> scripts(script_list(), isolate());
5139   DCHECK_IMPLIES(pretenure == TENURED, InOldSpace(*scripts));
5140   scripts = CompactWeakArrayList(this, scripts, pretenure);
5141   set_script_list(*scripts);
5142 
5143   Handle<WeakArrayList> no_script_list(noscript_shared_function_infos(),
5144                                        isolate());
5145   DCHECK_IMPLIES(pretenure == TENURED, InOldSpace(*no_script_list));
5146   no_script_list = CompactWeakArrayList(this, no_script_list, pretenure);
5147   set_noscript_shared_function_infos(*no_script_list);
5148 }
5149 
AddRetainedMap(Handle<Map> map)5150 void Heap::AddRetainedMap(Handle<Map> map) {
5151   if (map->is_in_retained_map_list()) {
5152     return;
5153   }
5154   Handle<WeakArrayList> array(retained_maps(), isolate());
5155   if (array->IsFull()) {
5156     CompactRetainedMaps(*array);
5157   }
5158   array =
5159       WeakArrayList::AddToEnd(isolate(), array, MaybeObjectHandle::Weak(map));
5160   array = WeakArrayList::AddToEnd(
5161       isolate(), array,
5162       MaybeObjectHandle(Smi::FromInt(FLAG_retain_maps_for_n_gc), isolate()));
5163   if (*array != retained_maps()) {
5164     set_retained_maps(*array);
5165   }
5166   map->set_is_in_retained_map_list(true);
5167 }
5168 
CompactRetainedMaps(WeakArrayList * retained_maps)5169 void Heap::CompactRetainedMaps(WeakArrayList* retained_maps) {
5170   DCHECK_EQ(retained_maps, this->retained_maps());
5171   int length = retained_maps->length();
5172   int new_length = 0;
5173   int new_number_of_disposed_maps = 0;
5174   // This loop compacts the array by removing cleared weak cells.
5175   for (int i = 0; i < length; i += 2) {
5176     MaybeObject* maybe_object = retained_maps->Get(i);
5177     if (maybe_object->IsClearedWeakHeapObject()) {
5178       continue;
5179     }
5180 
5181     DCHECK(maybe_object->IsWeakHeapObject());
5182 
5183     MaybeObject* age = retained_maps->Get(i + 1);
5184     DCHECK(age->IsSmi());
5185     if (i != new_length) {
5186       retained_maps->Set(new_length, maybe_object);
5187       retained_maps->Set(new_length + 1, age);
5188     }
5189     if (i < number_of_disposed_maps_) {
5190       new_number_of_disposed_maps += 2;
5191     }
5192     new_length += 2;
5193   }
5194   number_of_disposed_maps_ = new_number_of_disposed_maps;
5195   HeapObject* undefined = ReadOnlyRoots(this).undefined_value();
5196   for (int i = new_length; i < length; i++) {
5197     retained_maps->Set(i, HeapObjectReference::Strong(undefined));
5198   }
5199   if (new_length != length) retained_maps->set_length(new_length);
5200 }
5201 
FatalProcessOutOfMemory(const char * location)5202 void Heap::FatalProcessOutOfMemory(const char* location) {
5203   v8::internal::V8::FatalProcessOutOfMemory(isolate(), location, true);
5204 }
5205 
5206 #ifdef DEBUG
5207 
5208 class PrintHandleVisitor : public RootVisitor {
5209  public:
VisitRootPointers(Root root,const char * description,Object ** start,Object ** end)5210   void VisitRootPointers(Root root, const char* description, Object** start,
5211                          Object** end) override {
5212     for (Object** p = start; p < end; p++)
5213       PrintF("  handle %p to %p\n", reinterpret_cast<void*>(p),
5214              reinterpret_cast<void*>(*p));
5215   }
5216 };
5217 
5218 
PrintHandles()5219 void Heap::PrintHandles() {
5220   PrintF("Handles:\n");
5221   PrintHandleVisitor v;
5222   isolate_->handle_scope_implementer()->Iterate(&v);
5223 }
5224 
5225 #endif
5226 
5227 class CheckHandleCountVisitor : public RootVisitor {
5228  public:
CheckHandleCountVisitor()5229   CheckHandleCountVisitor() : handle_count_(0) {}
~CheckHandleCountVisitor()5230   ~CheckHandleCountVisitor() override {
5231     CHECK_GT(HandleScope::kCheckHandleThreshold, handle_count_);
5232   }
VisitRootPointers(Root root,const char * description,Object ** start,Object ** end)5233   void VisitRootPointers(Root root, const char* description, Object** start,
5234                          Object** end) override {
5235     handle_count_ += end - start;
5236   }
5237 
5238  private:
5239   ptrdiff_t handle_count_;
5240 };
5241 
5242 
CheckHandleCount()5243 void Heap::CheckHandleCount() {
5244   CheckHandleCountVisitor v;
5245   isolate_->handle_scope_implementer()->Iterate(&v);
5246 }
5247 
store_buffer_top_address()5248 Address* Heap::store_buffer_top_address() {
5249   return store_buffer()->top_address();
5250 }
5251 
5252 // static
store_buffer_mask_constant()5253 intptr_t Heap::store_buffer_mask_constant() {
5254   return StoreBuffer::kStoreBufferMask;
5255 }
5256 
5257 // static
store_buffer_overflow_function_address()5258 Address Heap::store_buffer_overflow_function_address() {
5259   return FUNCTION_ADDR(StoreBuffer::StoreBufferOverflow);
5260 }
5261 
ClearRecordedSlot(HeapObject * object,Object ** slot)5262 void Heap::ClearRecordedSlot(HeapObject* object, Object** slot) {
5263   Address slot_addr = reinterpret_cast<Address>(slot);
5264   Page* page = Page::FromAddress(slot_addr);
5265   if (!page->InNewSpace()) {
5266     DCHECK_EQ(page->owner()->identity(), OLD_SPACE);
5267     store_buffer()->DeleteEntry(slot_addr);
5268   }
5269 }
5270 
HasRecordedSlot(HeapObject * object,Object ** slot)5271 bool Heap::HasRecordedSlot(HeapObject* object, Object** slot) {
5272   if (InNewSpace(object)) {
5273     return false;
5274   }
5275   Address slot_addr = reinterpret_cast<Address>(slot);
5276   Page* page = Page::FromAddress(slot_addr);
5277   DCHECK_EQ(page->owner()->identity(), OLD_SPACE);
5278   store_buffer()->MoveAllEntriesToRememberedSet();
5279   return RememberedSet<OLD_TO_NEW>::Contains(page, slot_addr) ||
5280          RememberedSet<OLD_TO_OLD>::Contains(page, slot_addr);
5281 }
5282 
ClearRecordedSlotRange(Address start,Address end)5283 void Heap::ClearRecordedSlotRange(Address start, Address end) {
5284   Page* page = Page::FromAddress(start);
5285   if (!page->InNewSpace()) {
5286     DCHECK_EQ(page->owner()->identity(), OLD_SPACE);
5287     store_buffer()->DeleteEntry(start, end);
5288   }
5289 }
5290 
next()5291 PagedSpace* PagedSpaces::next() {
5292   switch (counter_++) {
5293     case RO_SPACE:
5294       // skip NEW_SPACE
5295       counter_++;
5296       return heap_->read_only_space();
5297     case OLD_SPACE:
5298       return heap_->old_space();
5299     case CODE_SPACE:
5300       return heap_->code_space();
5301     case MAP_SPACE:
5302       return heap_->map_space();
5303     default:
5304       return nullptr;
5305   }
5306 }
5307 
SpaceIterator(Heap * heap)5308 SpaceIterator::SpaceIterator(Heap* heap)
5309     : heap_(heap), current_space_(FIRST_SPACE - 1) {}
5310 
~SpaceIterator()5311 SpaceIterator::~SpaceIterator() {
5312 }
5313 
5314 
has_next()5315 bool SpaceIterator::has_next() {
5316   // Iterate until no more spaces.
5317   return current_space_ != LAST_SPACE;
5318 }
5319 
next()5320 Space* SpaceIterator::next() {
5321   DCHECK(has_next());
5322   return heap_->space(++current_space_);
5323 }
5324 
5325 
5326 class HeapObjectsFilter {
5327  public:
~HeapObjectsFilter()5328   virtual ~HeapObjectsFilter() {}
5329   virtual bool SkipObject(HeapObject* object) = 0;
5330 };
5331 
5332 
5333 class UnreachableObjectsFilter : public HeapObjectsFilter {
5334  public:
UnreachableObjectsFilter(Heap * heap)5335   explicit UnreachableObjectsFilter(Heap* heap) : heap_(heap) {
5336     MarkReachableObjects();
5337   }
5338 
~UnreachableObjectsFilter()5339   ~UnreachableObjectsFilter() {
5340     for (auto it : reachable_) {
5341       delete it.second;
5342       it.second = nullptr;
5343     }
5344   }
5345 
SkipObject(HeapObject * object)5346   bool SkipObject(HeapObject* object) {
5347     if (object->IsFiller()) return true;
5348     MemoryChunk* chunk = MemoryChunk::FromAddress(object->address());
5349     if (reachable_.count(chunk) == 0) return true;
5350     return reachable_[chunk]->count(object) == 0;
5351   }
5352 
5353  private:
MarkAsReachable(HeapObject * object)5354   bool MarkAsReachable(HeapObject* object) {
5355     MemoryChunk* chunk = MemoryChunk::FromAddress(object->address());
5356     if (reachable_.count(chunk) == 0) {
5357       reachable_[chunk] = new std::unordered_set<HeapObject*>();
5358     }
5359     if (reachable_[chunk]->count(object)) return false;
5360     reachable_[chunk]->insert(object);
5361     return true;
5362   }
5363 
5364   class MarkingVisitor : public ObjectVisitor, public RootVisitor {
5365    public:
MarkingVisitor(UnreachableObjectsFilter * filter)5366     explicit MarkingVisitor(UnreachableObjectsFilter* filter)
5367         : filter_(filter) {}
5368 
VisitPointers(HeapObject * host,Object ** start,Object ** end)5369     void VisitPointers(HeapObject* host, Object** start,
5370                        Object** end) override {
5371       MarkPointers(reinterpret_cast<MaybeObject**>(start),
5372                    reinterpret_cast<MaybeObject**>(end));
5373     }
5374 
VisitPointers(HeapObject * host,MaybeObject ** start,MaybeObject ** end)5375     void VisitPointers(HeapObject* host, MaybeObject** start,
5376                        MaybeObject** end) final {
5377       MarkPointers(start, end);
5378     }
5379 
VisitRootPointers(Root root,const char * description,Object ** start,Object ** end)5380     void VisitRootPointers(Root root, const char* description, Object** start,
5381                            Object** end) override {
5382       MarkPointers(reinterpret_cast<MaybeObject**>(start),
5383                    reinterpret_cast<MaybeObject**>(end));
5384     }
5385 
TransitiveClosure()5386     void TransitiveClosure() {
5387       while (!marking_stack_.empty()) {
5388         HeapObject* obj = marking_stack_.back();
5389         marking_stack_.pop_back();
5390         obj->Iterate(this);
5391       }
5392     }
5393 
5394    private:
MarkPointers(MaybeObject ** start,MaybeObject ** end)5395     void MarkPointers(MaybeObject** start, MaybeObject** end) {
5396       // Treat weak references as strong.
5397       for (MaybeObject** p = start; p < end; p++) {
5398         HeapObject* heap_object;
5399         if ((*p)->ToStrongOrWeakHeapObject(&heap_object)) {
5400           if (filter_->MarkAsReachable(heap_object)) {
5401             marking_stack_.push_back(heap_object);
5402           }
5403         }
5404       }
5405     }
5406     UnreachableObjectsFilter* filter_;
5407     std::vector<HeapObject*> marking_stack_;
5408   };
5409 
5410   friend class MarkingVisitor;
5411 
MarkReachableObjects()5412   void MarkReachableObjects() {
5413     MarkingVisitor visitor(this);
5414     heap_->IterateRoots(&visitor, VISIT_ALL);
5415     visitor.TransitiveClosure();
5416   }
5417 
5418   Heap* heap_;
5419   DisallowHeapAllocation no_allocation_;
5420   std::unordered_map<MemoryChunk*, std::unordered_set<HeapObject*>*> reachable_;
5421 };
5422 
HeapIterator(Heap * heap,HeapIterator::HeapObjectsFiltering filtering)5423 HeapIterator::HeapIterator(Heap* heap,
5424                            HeapIterator::HeapObjectsFiltering filtering)
5425     : no_heap_allocation_(),
5426       heap_(heap),
5427       filtering_(filtering),
5428       filter_(nullptr),
5429       space_iterator_(nullptr),
5430       object_iterator_(nullptr) {
5431   heap_->MakeHeapIterable();
5432   heap_->heap_iterator_start();
5433   // Start the iteration.
5434   space_iterator_ = new SpaceIterator(heap_);
5435   switch (filtering_) {
5436     case kFilterUnreachable:
5437       filter_ = new UnreachableObjectsFilter(heap_);
5438       break;
5439     default:
5440       break;
5441   }
5442   object_iterator_ = space_iterator_->next()->GetObjectIterator();
5443 }
5444 
5445 
~HeapIterator()5446 HeapIterator::~HeapIterator() {
5447   heap_->heap_iterator_end();
5448 #ifdef DEBUG
5449   // Assert that in filtering mode we have iterated through all
5450   // objects. Otherwise, heap will be left in an inconsistent state.
5451   if (filtering_ != kNoFiltering) {
5452     DCHECK_NULL(object_iterator_);
5453   }
5454 #endif
5455   delete space_iterator_;
5456   delete filter_;
5457 }
5458 
5459 
next()5460 HeapObject* HeapIterator::next() {
5461   if (filter_ == nullptr) return NextObject();
5462 
5463   HeapObject* obj = NextObject();
5464   while ((obj != nullptr) && (filter_->SkipObject(obj))) obj = NextObject();
5465   return obj;
5466 }
5467 
5468 
NextObject()5469 HeapObject* HeapIterator::NextObject() {
5470   // No iterator means we are done.
5471   if (object_iterator_.get() == nullptr) return nullptr;
5472 
5473   if (HeapObject* obj = object_iterator_.get()->Next()) {
5474     // If the current iterator has more objects we are fine.
5475     return obj;
5476   } else {
5477     // Go though the spaces looking for one that has objects.
5478     while (space_iterator_->has_next()) {
5479       object_iterator_ = space_iterator_->next()->GetObjectIterator();
5480       if (HeapObject* obj = object_iterator_.get()->Next()) {
5481         return obj;
5482       }
5483     }
5484   }
5485   // Done with the last space.
5486   object_iterator_.reset(nullptr);
5487   return nullptr;
5488 }
5489 
5490 
UpdateTotalGCTime(double duration)5491 void Heap::UpdateTotalGCTime(double duration) {
5492   if (FLAG_trace_gc_verbose) {
5493     total_gc_time_ms_ += duration;
5494   }
5495 }
5496 
CleanUpNewSpaceStrings()5497 void Heap::ExternalStringTable::CleanUpNewSpaceStrings() {
5498   int last = 0;
5499   Isolate* isolate = heap_->isolate();
5500   for (size_t i = 0; i < new_space_strings_.size(); ++i) {
5501     Object* o = new_space_strings_[i];
5502     if (o->IsTheHole(isolate)) {
5503       continue;
5504     }
5505     // The real external string is already in one of these vectors and was or
5506     // will be processed. Re-processing it will add a duplicate to the vector.
5507     if (o->IsThinString()) continue;
5508     DCHECK(o->IsExternalString());
5509     if (InNewSpace(o)) {
5510       new_space_strings_[last++] = o;
5511     } else {
5512       old_space_strings_.push_back(o);
5513     }
5514   }
5515   new_space_strings_.resize(last);
5516 }
5517 
CleanUpAll()5518 void Heap::ExternalStringTable::CleanUpAll() {
5519   CleanUpNewSpaceStrings();
5520   int last = 0;
5521   Isolate* isolate = heap_->isolate();
5522   for (size_t i = 0; i < old_space_strings_.size(); ++i) {
5523     Object* o = old_space_strings_[i];
5524     if (o->IsTheHole(isolate)) {
5525       continue;
5526     }
5527     // The real external string is already in one of these vectors and was or
5528     // will be processed. Re-processing it will add a duplicate to the vector.
5529     if (o->IsThinString()) continue;
5530     DCHECK(o->IsExternalString());
5531     DCHECK(!InNewSpace(o));
5532     old_space_strings_[last++] = o;
5533   }
5534   old_space_strings_.resize(last);
5535 #ifdef VERIFY_HEAP
5536   if (FLAG_verify_heap) {
5537     Verify();
5538   }
5539 #endif
5540 }
5541 
TearDown()5542 void Heap::ExternalStringTable::TearDown() {
5543   for (size_t i = 0; i < new_space_strings_.size(); ++i) {
5544     Object* o = new_space_strings_[i];
5545     // Dont finalize thin strings.
5546     if (o->IsThinString()) continue;
5547     heap_->FinalizeExternalString(ExternalString::cast(o));
5548   }
5549   new_space_strings_.clear();
5550   for (size_t i = 0; i < old_space_strings_.size(); ++i) {
5551     Object* o = old_space_strings_[i];
5552     // Dont finalize thin strings.
5553     if (o->IsThinString()) continue;
5554     heap_->FinalizeExternalString(ExternalString::cast(o));
5555   }
5556   old_space_strings_.clear();
5557 }
5558 
5559 
RememberUnmappedPage(Address page,bool compacted)5560 void Heap::RememberUnmappedPage(Address page, bool compacted) {
5561   // Tag the page pointer to make it findable in the dump file.
5562   if (compacted) {
5563     page ^= 0xC1EAD & (Page::kPageSize - 1);  // Cleared.
5564   } else {
5565     page ^= 0x1D1ED & (Page::kPageSize - 1);  // I died.
5566   }
5567   remembered_unmapped_pages_[remembered_unmapped_pages_index_] = page;
5568   remembered_unmapped_pages_index_++;
5569   remembered_unmapped_pages_index_ %= kRememberedUnmappedPages;
5570 }
5571 
RegisterStrongRoots(Object ** start,Object ** end)5572 void Heap::RegisterStrongRoots(Object** start, Object** end) {
5573   StrongRootsList* list = new StrongRootsList();
5574   list->next = strong_roots_list_;
5575   list->start = start;
5576   list->end = end;
5577   strong_roots_list_ = list;
5578 }
5579 
5580 
UnregisterStrongRoots(Object ** start)5581 void Heap::UnregisterStrongRoots(Object** start) {
5582   StrongRootsList* prev = nullptr;
5583   StrongRootsList* list = strong_roots_list_;
5584   while (list != nullptr) {
5585     StrongRootsList* next = list->next;
5586     if (list->start == start) {
5587       if (prev) {
5588         prev->next = next;
5589       } else {
5590         strong_roots_list_ = next;
5591       }
5592       delete list;
5593     } else {
5594       prev = list;
5595     }
5596     list = next;
5597   }
5598 }
5599 
IsDeserializeLazyHandler(Code * code)5600 bool Heap::IsDeserializeLazyHandler(Code* code) {
5601   return (code == deserialize_lazy_handler() ||
5602           code == deserialize_lazy_handler_wide() ||
5603           code == deserialize_lazy_handler_extra_wide());
5604 }
5605 
SetDeserializeLazyHandler(Code * code)5606 void Heap::SetDeserializeLazyHandler(Code* code) {
5607   set_deserialize_lazy_handler(code);
5608 }
5609 
SetDeserializeLazyHandlerWide(Code * code)5610 void Heap::SetDeserializeLazyHandlerWide(Code* code) {
5611   set_deserialize_lazy_handler_wide(code);
5612 }
5613 
SetDeserializeLazyHandlerExtraWide(Code * code)5614 void Heap::SetDeserializeLazyHandlerExtraWide(Code* code) {
5615   set_deserialize_lazy_handler_extra_wide(code);
5616 }
5617 
SetBuiltinsConstantsTable(FixedArray * cache)5618 void Heap::SetBuiltinsConstantsTable(FixedArray* cache) {
5619   set_builtins_constants_table(cache);
5620 }
5621 
NumberOfTrackedHeapObjectTypes()5622 size_t Heap::NumberOfTrackedHeapObjectTypes() {
5623   return ObjectStats::OBJECT_STATS_COUNT;
5624 }
5625 
5626 
ObjectCountAtLastGC(size_t index)5627 size_t Heap::ObjectCountAtLastGC(size_t index) {
5628   if (live_object_stats_ == nullptr || index >= ObjectStats::OBJECT_STATS_COUNT)
5629     return 0;
5630   return live_object_stats_->object_count_last_gc(index);
5631 }
5632 
5633 
ObjectSizeAtLastGC(size_t index)5634 size_t Heap::ObjectSizeAtLastGC(size_t index) {
5635   if (live_object_stats_ == nullptr || index >= ObjectStats::OBJECT_STATS_COUNT)
5636     return 0;
5637   return live_object_stats_->object_size_last_gc(index);
5638 }
5639 
5640 
GetObjectTypeName(size_t index,const char ** object_type,const char ** object_sub_type)5641 bool Heap::GetObjectTypeName(size_t index, const char** object_type,
5642                              const char** object_sub_type) {
5643   if (index >= ObjectStats::OBJECT_STATS_COUNT) return false;
5644 
5645   switch (static_cast<int>(index)) {
5646 #define COMPARE_AND_RETURN_NAME(name) \
5647   case name:                          \
5648     *object_type = #name;             \
5649     *object_sub_type = "";            \
5650     return true;
5651     INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME)
5652 #undef COMPARE_AND_RETURN_NAME
5653 
5654 #define COMPARE_AND_RETURN_NAME(name)                       \
5655   case ObjectStats::FIRST_VIRTUAL_TYPE + ObjectStats::name: \
5656     *object_type = #name;                                   \
5657     *object_sub_type = "";                                  \
5658     return true;
5659     VIRTUAL_INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME)
5660 #undef COMPARE_AND_RETURN_NAME
5661   }
5662   return false;
5663 }
5664 
NumberOfNativeContexts()5665 size_t Heap::NumberOfNativeContexts() {
5666   int result = 0;
5667   Object* context = native_contexts_list();
5668   while (!context->IsUndefined(isolate())) {
5669     ++result;
5670     Context* native_context = Context::cast(context);
5671     context = native_context->next_context_link();
5672   }
5673   return result;
5674 }
5675 
NumberOfDetachedContexts()5676 size_t Heap::NumberOfDetachedContexts() {
5677   // The detached_contexts() array has two entries per detached context.
5678   return detached_contexts()->length() / 2;
5679 }
5680 
AllocationSpaceName(AllocationSpace space)5681 const char* AllocationSpaceName(AllocationSpace space) {
5682   switch (space) {
5683     case NEW_SPACE:
5684       return "NEW_SPACE";
5685     case OLD_SPACE:
5686       return "OLD_SPACE";
5687     case CODE_SPACE:
5688       return "CODE_SPACE";
5689     case MAP_SPACE:
5690       return "MAP_SPACE";
5691     case LO_SPACE:
5692       return "LO_SPACE";
5693     case NEW_LO_SPACE:
5694       return "NEW_LO_SPACE";
5695     case RO_SPACE:
5696       return "RO_SPACE";
5697     default:
5698       UNREACHABLE();
5699   }
5700   return nullptr;
5701 }
5702 
VisitPointers(HeapObject * host,Object ** start,Object ** end)5703 void VerifyPointersVisitor::VisitPointers(HeapObject* host, Object** start,
5704                                           Object** end) {
5705   VerifyPointers(host, reinterpret_cast<MaybeObject**>(start),
5706                  reinterpret_cast<MaybeObject**>(end));
5707 }
5708 
VisitPointers(HeapObject * host,MaybeObject ** start,MaybeObject ** end)5709 void VerifyPointersVisitor::VisitPointers(HeapObject* host, MaybeObject** start,
5710                                           MaybeObject** end) {
5711   VerifyPointers(host, start, end);
5712 }
5713 
VisitRootPointers(Root root,const char * description,Object ** start,Object ** end)5714 void VerifyPointersVisitor::VisitRootPointers(Root root,
5715                                               const char* description,
5716                                               Object** start, Object** end) {
5717   VerifyPointers(nullptr, reinterpret_cast<MaybeObject**>(start),
5718                  reinterpret_cast<MaybeObject**>(end));
5719 }
5720 
VerifyPointers(HeapObject * host,MaybeObject ** start,MaybeObject ** end)5721 void VerifyPointersVisitor::VerifyPointers(HeapObject* host,
5722                                            MaybeObject** start,
5723                                            MaybeObject** end) {
5724   for (MaybeObject** current = start; current < end; current++) {
5725     HeapObject* object;
5726     if ((*current)->ToStrongOrWeakHeapObject(&object)) {
5727       CHECK(heap_->Contains(object));
5728       CHECK(object->map()->IsMap());
5729     } else {
5730       CHECK((*current)->IsSmi() || (*current)->IsClearedWeakHeapObject());
5731     }
5732   }
5733 }
5734 
VisitRootPointers(Root root,const char * description,Object ** start,Object ** end)5735 void VerifySmisVisitor::VisitRootPointers(Root root, const char* description,
5736                                           Object** start, Object** end) {
5737   for (Object** current = start; current < end; current++) {
5738     CHECK((*current)->IsSmi());
5739   }
5740 }
5741 
AllowedToBeMigrated(HeapObject * obj,AllocationSpace dst)5742 bool Heap::AllowedToBeMigrated(HeapObject* obj, AllocationSpace dst) {
5743   // Object migration is governed by the following rules:
5744   //
5745   // 1) Objects in new-space can be migrated to the old space
5746   //    that matches their target space or they stay in new-space.
5747   // 2) Objects in old-space stay in the same space when migrating.
5748   // 3) Fillers (two or more words) can migrate due to left-trimming of
5749   //    fixed arrays in new-space or old space.
5750   // 4) Fillers (one word) can never migrate, they are skipped by
5751   //    incremental marking explicitly to prevent invalid pattern.
5752   //
5753   // Since this function is used for debugging only, we do not place
5754   // asserts here, but check everything explicitly.
5755   if (obj->map() == ReadOnlyRoots(this).one_pointer_filler_map()) return false;
5756   InstanceType type = obj->map()->instance_type();
5757   MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
5758   AllocationSpace src = chunk->owner()->identity();
5759   switch (src) {
5760     case NEW_SPACE:
5761       return dst == NEW_SPACE || dst == OLD_SPACE;
5762     case OLD_SPACE:
5763       return dst == OLD_SPACE;
5764     case CODE_SPACE:
5765       return dst == CODE_SPACE && type == CODE_TYPE;
5766     case MAP_SPACE:
5767     case LO_SPACE:
5768     case NEW_LO_SPACE:
5769     case RO_SPACE:
5770       return false;
5771   }
5772   UNREACHABLE();
5773 }
5774 
CreateObjectStats()5775 void Heap::CreateObjectStats() {
5776   if (V8_LIKELY(FLAG_gc_stats == 0)) return;
5777   if (!live_object_stats_) {
5778     live_object_stats_ = new ObjectStats(this);
5779   }
5780   if (!dead_object_stats_) {
5781     dead_object_stats_ = new ObjectStats(this);
5782   }
5783 }
5784 
AllocationStep(int bytes_allocated,Address soon_object,size_t size)5785 void AllocationObserver::AllocationStep(int bytes_allocated,
5786                                         Address soon_object, size_t size) {
5787   DCHECK_GE(bytes_allocated, 0);
5788   bytes_to_next_step_ -= bytes_allocated;
5789   if (bytes_to_next_step_ <= 0) {
5790     Step(static_cast<int>(step_size_ - bytes_to_next_step_), soon_object, size);
5791     step_size_ = GetNextStepSize();
5792     bytes_to_next_step_ = step_size_;
5793   }
5794   DCHECK_GE(bytes_to_next_step_, 0);
5795 }
5796 
5797 namespace {
5798 
GcSafeMapOfCodeSpaceObject(HeapObject * object)5799 Map* GcSafeMapOfCodeSpaceObject(HeapObject* object) {
5800   MapWord map_word = object->map_word();
5801   return map_word.IsForwardingAddress() ? map_word.ToForwardingAddress()->map()
5802                                         : map_word.ToMap();
5803 }
5804 
GcSafeSizeOfCodeSpaceObject(HeapObject * object)5805 int GcSafeSizeOfCodeSpaceObject(HeapObject* object) {
5806   return object->SizeFromMap(GcSafeMapOfCodeSpaceObject(object));
5807 }
5808 
GcSafeCastToCode(Heap * heap,HeapObject * object,Address inner_pointer)5809 Code* GcSafeCastToCode(Heap* heap, HeapObject* object, Address inner_pointer) {
5810   Code* code = reinterpret_cast<Code*>(object);
5811   DCHECK_NOT_NULL(code);
5812   DCHECK(heap->GcSafeCodeContains(code, inner_pointer));
5813   return code;
5814 }
5815 
5816 }  // namespace
5817 
GcSafeCodeContains(HeapObject * code,Address addr)5818 bool Heap::GcSafeCodeContains(HeapObject* code, Address addr) {
5819   Map* map = GcSafeMapOfCodeSpaceObject(code);
5820   DCHECK(map == ReadOnlyRoots(this).code_map());
5821   if (InstructionStream::TryLookupCode(isolate(), addr) == code) return true;
5822   Address start = code->address();
5823   Address end = code->address() + code->SizeFromMap(map);
5824   return start <= addr && addr < end;
5825 }
5826 
GcSafeFindCodeForInnerPointer(Address inner_pointer)5827 Code* Heap::GcSafeFindCodeForInnerPointer(Address inner_pointer) {
5828   Code* code = InstructionStream::TryLookupCode(isolate(), inner_pointer);
5829   if (code != nullptr) return code;
5830 
5831   // Check if the inner pointer points into a large object chunk.
5832   LargePage* large_page = lo_space()->FindPage(inner_pointer);
5833   if (large_page != nullptr) {
5834     return GcSafeCastToCode(this, large_page->GetObject(), inner_pointer);
5835   }
5836 
5837   DCHECK(code_space()->Contains(inner_pointer));
5838 
5839   // Iterate through the page until we reach the end or find an object starting
5840   // after the inner pointer.
5841   Page* page = Page::FromAddress(inner_pointer);
5842   DCHECK_EQ(page->owner(), code_space());
5843   mark_compact_collector()->sweeper()->EnsurePageIsIterable(page);
5844 
5845   Address addr = page->skip_list()->StartFor(inner_pointer);
5846   Address top = code_space()->top();
5847   Address limit = code_space()->limit();
5848 
5849   while (true) {
5850     if (addr == top && addr != limit) {
5851       addr = limit;
5852       continue;
5853     }
5854 
5855     HeapObject* obj = HeapObject::FromAddress(addr);
5856     int obj_size = GcSafeSizeOfCodeSpaceObject(obj);
5857     Address next_addr = addr + obj_size;
5858     if (next_addr > inner_pointer)
5859       return GcSafeCastToCode(this, obj, inner_pointer);
5860     addr = next_addr;
5861   }
5862 }
5863 
WriteBarrierForCodeSlow(Code * code)5864 void Heap::WriteBarrierForCodeSlow(Code* code) {
5865   for (RelocIterator it(code, RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT));
5866        !it.done(); it.next()) {
5867     GenerationalBarrierForCode(code, it.rinfo(), it.rinfo()->target_object());
5868     MarkingBarrierForCode(code, it.rinfo(), it.rinfo()->target_object());
5869   }
5870 }
5871 
GenerationalBarrierSlow(HeapObject * object,Address slot,HeapObject * value)5872 void Heap::GenerationalBarrierSlow(HeapObject* object, Address slot,
5873                                    HeapObject* value) {
5874   Heap* heap = Heap::FromWritableHeapObject(object);
5875   heap->store_buffer()->InsertEntry(slot);
5876 }
5877 
GenerationalBarrierForElementsSlow(Heap * heap,FixedArray * array,int offset,int length)5878 void Heap::GenerationalBarrierForElementsSlow(Heap* heap, FixedArray* array,
5879                                               int offset, int length) {
5880   for (int i = 0; i < length; i++) {
5881     if (!InNewSpace(array->get(offset + i))) continue;
5882     heap->store_buffer()->InsertEntry(
5883         reinterpret_cast<Address>(array->RawFieldOfElementAt(offset + i)));
5884   }
5885 }
5886 
GenerationalBarrierForCodeSlow(Code * host,RelocInfo * rinfo,HeapObject * object)5887 void Heap::GenerationalBarrierForCodeSlow(Code* host, RelocInfo* rinfo,
5888                                           HeapObject* object) {
5889   DCHECK(InNewSpace(object));
5890   Page* source_page = Page::FromAddress(reinterpret_cast<Address>(host));
5891   RelocInfo::Mode rmode = rinfo->rmode();
5892   Address addr = rinfo->pc();
5893   SlotType slot_type = SlotTypeForRelocInfoMode(rmode);
5894   if (rinfo->IsInConstantPool()) {
5895     addr = rinfo->constant_pool_entry_address();
5896     if (RelocInfo::IsCodeTargetMode(rmode)) {
5897       slot_type = CODE_ENTRY_SLOT;
5898     } else {
5899       DCHECK(RelocInfo::IsEmbeddedObject(rmode));
5900       slot_type = OBJECT_SLOT;
5901     }
5902   }
5903   RememberedSet<OLD_TO_NEW>::InsertTyped(
5904       source_page, reinterpret_cast<Address>(host), slot_type, addr);
5905 }
5906 
MarkingBarrierSlow(HeapObject * object,Address slot,HeapObject * value)5907 void Heap::MarkingBarrierSlow(HeapObject* object, Address slot,
5908                               HeapObject* value) {
5909   Heap* heap = Heap::FromWritableHeapObject(object);
5910   heap->incremental_marking()->RecordWriteSlow(
5911       object, reinterpret_cast<HeapObjectReference**>(slot), value);
5912 }
5913 
MarkingBarrierForElementsSlow(Heap * heap,HeapObject * object)5914 void Heap::MarkingBarrierForElementsSlow(Heap* heap, HeapObject* object) {
5915   if (FLAG_concurrent_marking ||
5916       heap->incremental_marking()->marking_state()->IsBlack(object)) {
5917     heap->incremental_marking()->RevisitObject(object);
5918   }
5919 }
5920 
MarkingBarrierForCodeSlow(Code * host,RelocInfo * rinfo,HeapObject * object)5921 void Heap::MarkingBarrierForCodeSlow(Code* host, RelocInfo* rinfo,
5922                                      HeapObject* object) {
5923   Heap* heap = Heap::FromWritableHeapObject(host);
5924   DCHECK(heap->incremental_marking()->IsMarking());
5925   heap->incremental_marking()->RecordWriteIntoCode(host, rinfo, object);
5926 }
5927 
PageFlagsAreConsistent(HeapObject * object)5928 bool Heap::PageFlagsAreConsistent(HeapObject* object) {
5929   Heap* heap = Heap::FromWritableHeapObject(object);
5930   MemoryChunk* chunk = MemoryChunk::FromHeapObject(object);
5931   heap_internals::MemoryChunk* slim_chunk =
5932       heap_internals::MemoryChunk::FromHeapObject(object);
5933 
5934   const bool generation_consistency =
5935       chunk->owner()->identity() != NEW_SPACE ||
5936       (chunk->InNewSpace() && slim_chunk->InNewSpace());
5937   const bool marking_consistency =
5938       !heap->incremental_marking()->IsMarking() ||
5939       (chunk->IsFlagSet(MemoryChunk::INCREMENTAL_MARKING) &&
5940        slim_chunk->IsMarking());
5941 
5942   return generation_consistency && marking_consistency;
5943 }
5944 
5945 static_assert(MemoryChunk::Flag::INCREMENTAL_MARKING ==
5946                   heap_internals::MemoryChunk::kMarkingBit,
5947               "Incremental marking flag inconsistent");
5948 static_assert(MemoryChunk::Flag::IN_FROM_SPACE ==
5949                   heap_internals::MemoryChunk::kFromSpaceBit,
5950               "From space flag inconsistent");
5951 static_assert(MemoryChunk::Flag::IN_TO_SPACE ==
5952                   heap_internals::MemoryChunk::kToSpaceBit,
5953               "To space flag inconsistent");
5954 static_assert(MemoryChunk::kFlagsOffset ==
5955                   heap_internals::MemoryChunk::kFlagsOffset,
5956               "Flag offset inconsistent");
5957 
SetEmbedderStackStateForNextFinalizaton(EmbedderHeapTracer::EmbedderStackState stack_state)5958 void Heap::SetEmbedderStackStateForNextFinalizaton(
5959     EmbedderHeapTracer::EmbedderStackState stack_state) {
5960   local_embedder_heap_tracer()->SetEmbedderStackStateForNextFinalization(
5961       stack_state);
5962 }
5963 
5964 }  // namespace internal
5965 }  // namespace v8
5966