• 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/incremental-marking-job.h"
6 
7 #include "src/base/platform/mutex.h"
8 #include "src/base/platform/time.h"
9 #include "src/execution/isolate.h"
10 #include "src/execution/vm-state-inl.h"
11 #include "src/heap/embedder-tracing.h"
12 #include "src/heap/gc-tracer.h"
13 #include "src/heap/heap-inl.h"
14 #include "src/heap/heap.h"
15 #include "src/heap/incremental-marking.h"
16 #include "src/init/v8.h"
17 
18 namespace v8 {
19 namespace internal {
20 
21 class IncrementalMarkingJob::Task : public CancelableTask {
22  public:
23   static StepResult Step(Heap* heap);
24 
Task(Isolate * isolate,IncrementalMarkingJob * job,EmbedderHeapTracer::EmbedderStackState stack_state,TaskType task_type)25   Task(Isolate* isolate, IncrementalMarkingJob* job,
26        EmbedderHeapTracer::EmbedderStackState stack_state, TaskType task_type)
27       : CancelableTask(isolate),
28         isolate_(isolate),
29         job_(job),
30         stack_state_(stack_state),
31         task_type_(task_type) {}
32 
33   // CancelableTask overrides.
34   void RunInternal() override;
35 
isolate() const36   Isolate* isolate() const { return isolate_; }
37 
38  private:
39   Isolate* const isolate_;
40   IncrementalMarkingJob* const job_;
41   const EmbedderHeapTracer::EmbedderStackState stack_state_;
42   const TaskType task_type_;
43 };
44 
Start(Heap * heap)45 void IncrementalMarkingJob::Start(Heap* heap) {
46   DCHECK(!heap->incremental_marking()->IsStopped());
47   ScheduleTask(heap);
48 }
49 
ScheduleTask(Heap * heap,TaskType task_type)50 void IncrementalMarkingJob::ScheduleTask(Heap* heap, TaskType task_type) {
51   base::MutexGuard guard(&mutex_);
52 
53   if (!IsTaskPending(task_type) && !heap->IsTearingDown() &&
54       FLAG_incremental_marking_task) {
55     v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap->isolate());
56     SetTaskPending(task_type, true);
57     auto taskrunner =
58         V8::GetCurrentPlatform()->GetForegroundTaskRunner(isolate);
59     const EmbedderHeapTracer::EmbedderStackState stack_state =
60         taskrunner->NonNestableTasksEnabled()
61             ? EmbedderHeapTracer::EmbedderStackState::kNoHeapPointers
62             : EmbedderHeapTracer::EmbedderStackState::kMayContainHeapPointers;
63     auto task =
64         std::make_unique<Task>(heap->isolate(), this, stack_state, task_type);
65     if (task_type == TaskType::kNormal) {
66       scheduled_time_ = heap->MonotonicallyIncreasingTimeInMs();
67       if (taskrunner->NonNestableTasksEnabled()) {
68         taskrunner->PostNonNestableTask(std::move(task));
69       } else {
70         taskrunner->PostTask(std::move(task));
71       }
72     } else {
73       if (taskrunner->NonNestableDelayedTasksEnabled()) {
74         taskrunner->PostNonNestableDelayedTask(std::move(task),
75                                                kDelayInSeconds);
76       } else {
77         taskrunner->PostDelayedTask(std::move(task), kDelayInSeconds);
78       }
79     }
80   }
81 }
82 
Step(Heap * heap)83 StepResult IncrementalMarkingJob::Task::Step(Heap* heap) {
84   const int kIncrementalMarkingDelayMs = 1;
85   double deadline =
86       heap->MonotonicallyIncreasingTimeInMs() + kIncrementalMarkingDelayMs;
87   StepResult result = heap->incremental_marking()->AdvanceWithDeadline(
88       deadline, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD,
89       i::StepOrigin::kTask);
90   heap->FinalizeIncrementalMarkingIfComplete(
91       GarbageCollectionReason::kFinalizeMarkingViaTask);
92   return result;
93 }
94 
RunInternal()95 void IncrementalMarkingJob::Task::RunInternal() {
96   VMState<GC> state(isolate());
97   TRACE_EVENT_CALL_STATS_SCOPED(isolate(), "v8", "V8.Task");
98 
99   Heap* heap = isolate()->heap();
100   EmbedderStackStateScope scope(heap->local_embedder_heap_tracer(),
101                                 stack_state_);
102   if (task_type_ == TaskType::kNormal) {
103     heap->tracer()->RecordTimeToIncrementalMarkingTask(
104         heap->MonotonicallyIncreasingTimeInMs() - job_->scheduled_time_);
105     job_->scheduled_time_ = 0.0;
106   }
107   IncrementalMarking* incremental_marking = heap->incremental_marking();
108   if (incremental_marking->IsStopped()) {
109     if (heap->IncrementalMarkingLimitReached() !=
110         Heap::IncrementalMarkingLimit::kNoLimit) {
111       heap->StartIncrementalMarking(heap->GCFlagsForIncrementalMarking(),
112                                     GarbageCollectionReason::kTask,
113                                     kGCCallbackScheduleIdleGarbageCollection);
114     }
115   }
116 
117   // Clear this flag after StartIncrementalMarking call to avoid
118   // scheduling a new task when starting incremental marking.
119   {
120     base::MutexGuard guard(&job_->mutex_);
121     job_->SetTaskPending(task_type_, false);
122   }
123 
124   if (!incremental_marking->IsStopped()) {
125     // All objects are initialized at that point.
126     heap->new_space()->MarkLabStartInitialized();
127     heap->new_lo_space()->ResetPendingObject();
128     StepResult step_result = Step(heap);
129     if (!incremental_marking->IsStopped()) {
130       const TaskType task_type =
131           incremental_marking->finalize_marking_completed() ||
132                   step_result != StepResult::kNoImmediateWork
133               ? TaskType::kNormal
134               : TaskType::kDelayed;
135       job_->ScheduleTask(heap, task_type);
136     }
137   }
138 }
139 
CurrentTimeToTask(Heap * heap) const140 double IncrementalMarkingJob::CurrentTimeToTask(Heap* heap) const {
141   if (scheduled_time_ == 0.0) return 0.0;
142 
143   return heap->MonotonicallyIncreasingTimeInMs() - scheduled_time_;
144 }
145 
146 }  // namespace internal
147 }  // namespace v8
148