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