incremental-marking-job.cc 4.93 KB
Newer Older
1 2 3 4 5 6
// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/heap/incremental-marking-job.h"

7
#include "src/base/platform/mutex.h"
8
#include "src/base/platform/time.h"
9 10
#include "src/execution/isolate.h"
#include "src/execution/vm-state-inl.h"
11
#include "src/heap/embedder-tracing.h"
12
#include "src/heap/gc-tracer.h"
13 14 15
#include "src/heap/heap-inl.h"
#include "src/heap/heap.h"
#include "src/heap/incremental-marking.h"
16
#include "src/init/v8.h"
17 18 19 20

namespace v8 {
namespace internal {

21 22
class IncrementalMarkingJob::Task : public CancelableTask {
 public:
23
  static StepResult Step(Heap* heap);
24 25

  Task(Isolate* isolate, IncrementalMarkingJob* job,
26
       EmbedderHeapTracer::EmbedderStackState stack_state, TaskType task_type)
27 28 29
      : CancelableTask(isolate),
        isolate_(isolate),
        job_(job),
30 31
        stack_state_(stack_state),
        task_type_(task_type) {}
32 33 34 35 36 37 38 39 40 41

  // CancelableTask overrides.
  void RunInternal() override;

  Isolate* isolate() const { return isolate_; }

 private:
  Isolate* const isolate_;
  IncrementalMarkingJob* const job_;
  const EmbedderHeapTracer::EmbedderStackState stack_state_;
42
  const TaskType task_type_;
43 44
};

45 46
void IncrementalMarkingJob::Start(Heap* heap) {
  DCHECK(!heap->incremental_marking()->IsStopped());
47
  ScheduleTask(heap);
48 49
}

50
void IncrementalMarkingJob::ScheduleTask(Heap* heap, TaskType task_type) {
51 52
  base::MutexGuard guard(&mutex_);

53 54
  if (!IsTaskPending(task_type) && !heap->IsTearingDown() &&
      FLAG_incremental_marking_task) {
55
    v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap->isolate());
56
    SetTaskPending(task_type, true);
57 58
    auto taskrunner =
        V8::GetCurrentPlatform()->GetForegroundTaskRunner(isolate);
59 60
    const EmbedderHeapTracer::EmbedderStackState stack_state =
        taskrunner->NonNestableTasksEnabled()
61 62
            ? EmbedderHeapTracer::EmbedderStackState::kNoHeapPointers
            : EmbedderHeapTracer::EmbedderStackState::kMayContainHeapPointers;
63 64
    auto task =
        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 75
        taskrunner->PostNonNestableDelayedTask(std::move(task),
                                               kDelayInSeconds);
76
      } else {
77
        taskrunner->PostDelayedTask(std::move(task), kDelayInSeconds);
78
      }
79
    }
80 81 82
  }
}

83
StepResult IncrementalMarkingJob::Task::Step(Heap* heap) {
84
  const int kIncrementalMarkingDelayMs = 1;
85 86
  double deadline =
      heap->MonotonicallyIncreasingTimeInMs() + kIncrementalMarkingDelayMs;
87
  StepResult result = heap->incremental_marking()->AdvanceWithDeadline(
88
      deadline, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD,
89
      i::StepOrigin::kTask);
90 91
  heap->FinalizeIncrementalMarkingIfComplete(
      GarbageCollectionReason::kFinalizeMarkingViaTask);
92
  return result;
93 94
}

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 101
  EmbedderStackStateScope scope(heap->local_embedder_heap_tracer(),
                                stack_state_);
102 103 104 105 106
  if (task_type_ == TaskType::kNormal) {
    heap->tracer()->RecordTimeToIncrementalMarkingTask(
        heap->MonotonicallyIncreasingTimeInMs() - job_->scheduled_time_);
    job_->scheduled_time_ = 0.0;
  }
107
  IncrementalMarking* incremental_marking = heap->incremental_marking();
108 109 110
  if (incremental_marking->IsStopped()) {
    if (heap->IncrementalMarkingLimitReached() !=
        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 119 120 121 122
  // scheduling a new task when starting incremental marking.
  {
    base::MutexGuard guard(&job_->mutex_);
    job_->SetTaskPending(task_type_, false);
  }
123

124
  if (!incremental_marking->IsStopped()) {
125
    StepResult step_result = Step(heap);
126
    if (!incremental_marking->IsStopped()) {
127 128 129 130 131 132
      const TaskType task_type =
          incremental_marking->finalize_marking_completed() ||
                  step_result != StepResult::kNoImmediateWork
              ? TaskType::kNormal
              : TaskType::kDelayed;
      job_->ScheduleTask(heap, task_type);
133 134 135 136
    }
  }
}

137 138 139 140 141 142
double IncrementalMarkingJob::CurrentTimeToTask(Heap* heap) const {
  if (scheduled_time_ == 0.0) return 0.0;

  return heap->MonotonicallyIncreasingTimeInMs() - scheduled_time_;
}

143 144
}  // namespace internal
}  // namespace v8