| // 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" | 
 |  | 
 | #include "src/base/platform/mutex.h" | 
 | #include "src/base/platform/time.h" | 
 | #include "src/execution/isolate.h" | 
 | #include "src/execution/vm-state-inl.h" | 
 | #include "src/heap/embedder-tracing.h" | 
 | #include "src/heap/gc-tracer.h" | 
 | #include "src/heap/heap-inl.h" | 
 | #include "src/heap/heap.h" | 
 | #include "src/heap/incremental-marking.h" | 
 | #include "src/init/v8.h" | 
 |  | 
 | namespace v8 { | 
 | namespace internal { | 
 |  | 
 | class IncrementalMarkingJob::Task : public CancelableTask { | 
 |  public: | 
 |   static StepResult Step(Heap* heap); | 
 |  | 
 |   Task(Isolate* isolate, IncrementalMarkingJob* job, | 
 |        EmbedderHeapTracer::EmbedderStackState stack_state, TaskType task_type) | 
 |       : CancelableTask(isolate), | 
 |         isolate_(isolate), | 
 |         job_(job), | 
 |         stack_state_(stack_state), | 
 |         task_type_(task_type) {} | 
 |  | 
 |   // CancelableTask overrides. | 
 |   void RunInternal() override; | 
 |  | 
 |   Isolate* isolate() const { return isolate_; } | 
 |  | 
 |  private: | 
 |   Isolate* const isolate_; | 
 |   IncrementalMarkingJob* const job_; | 
 |   const EmbedderHeapTracer::EmbedderStackState stack_state_; | 
 |   const TaskType task_type_; | 
 | }; | 
 |  | 
 | void IncrementalMarkingJob::Start(Heap* heap) { | 
 |   DCHECK(!heap->incremental_marking()->IsStopped()); | 
 |   ScheduleTask(heap); | 
 | } | 
 |  | 
 | void IncrementalMarkingJob::ScheduleTask(Heap* heap, TaskType task_type) { | 
 |   base::MutexGuard guard(&mutex_); | 
 |  | 
 |   if (!IsTaskPending(task_type) && !heap->IsTearingDown() && | 
 |       FLAG_incremental_marking_task) { | 
 |     v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap->isolate()); | 
 |     SetTaskPending(task_type, true); | 
 |     auto taskrunner = | 
 |         V8::GetCurrentPlatform()->GetForegroundTaskRunner(isolate); | 
 |     const EmbedderHeapTracer::EmbedderStackState stack_state = | 
 |         taskrunner->NonNestableTasksEnabled() | 
 |             ? EmbedderHeapTracer::EmbedderStackState::kNoHeapPointers | 
 |             : EmbedderHeapTracer::EmbedderStackState::kMayContainHeapPointers; | 
 |     auto task = | 
 |         std::make_unique<Task>(heap->isolate(), this, stack_state, task_type); | 
 |     if (task_type == TaskType::kNormal) { | 
 |       scheduled_time_ = heap->MonotonicallyIncreasingTimeInMs(); | 
 |       if (taskrunner->NonNestableTasksEnabled()) { | 
 |         taskrunner->PostNonNestableTask(std::move(task)); | 
 |       } else { | 
 |         taskrunner->PostTask(std::move(task)); | 
 |       } | 
 |     } else { | 
 |       if (taskrunner->NonNestableDelayedTasksEnabled()) { | 
 |         taskrunner->PostNonNestableDelayedTask(std::move(task), | 
 |                                                kDelayInSeconds); | 
 |       } else { | 
 |         taskrunner->PostDelayedTask(std::move(task), kDelayInSeconds); | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | StepResult IncrementalMarkingJob::Task::Step(Heap* heap) { | 
 |   const int kIncrementalMarkingDelayMs = 1; | 
 |   double deadline = | 
 |       heap->MonotonicallyIncreasingTimeInMs() + kIncrementalMarkingDelayMs; | 
 |   StepResult result = heap->incremental_marking()->AdvanceWithDeadline( | 
 |       deadline, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD, | 
 |       i::StepOrigin::kTask); | 
 |   heap->FinalizeIncrementalMarkingIfComplete( | 
 |       GarbageCollectionReason::kFinalizeMarkingViaTask); | 
 |   return result; | 
 | } | 
 |  | 
 | void IncrementalMarkingJob::Task::RunInternal() { | 
 |   VMState<GC> state(isolate()); | 
 |   TRACE_EVENT_CALL_STATS_SCOPED(isolate(), "v8", "V8.Task"); | 
 |  | 
 |   Heap* heap = isolate()->heap(); | 
 |   EmbedderStackStateScope scope(heap->local_embedder_heap_tracer(), | 
 |                                 stack_state_); | 
 |   if (task_type_ == TaskType::kNormal) { | 
 |     heap->tracer()->RecordTimeToIncrementalMarkingTask( | 
 |         heap->MonotonicallyIncreasingTimeInMs() - job_->scheduled_time_); | 
 |     job_->scheduled_time_ = 0.0; | 
 |   } | 
 |   IncrementalMarking* incremental_marking = heap->incremental_marking(); | 
 |   if (incremental_marking->IsStopped()) { | 
 |     if (heap->IncrementalMarkingLimitReached() != | 
 |         Heap::IncrementalMarkingLimit::kNoLimit) { | 
 |       heap->StartIncrementalMarking(heap->GCFlagsForIncrementalMarking(), | 
 |                                     GarbageCollectionReason::kTask, | 
 |                                     kGCCallbackScheduleIdleGarbageCollection); | 
 |     } | 
 |   } | 
 |  | 
 |   // Clear this flag after StartIncrementalMarking call to avoid | 
 |   // scheduling a new task when starting incremental marking. | 
 |   { | 
 |     base::MutexGuard guard(&job_->mutex_); | 
 |     job_->SetTaskPending(task_type_, false); | 
 |   } | 
 |  | 
 |   if (!incremental_marking->IsStopped()) { | 
 |     // All objects are initialized at that point. | 
 |     heap->new_space()->MarkLabStartInitialized(); | 
 |     heap->new_lo_space()->ResetPendingObject(); | 
 |     StepResult step_result = Step(heap); | 
 |     if (!incremental_marking->IsStopped()) { | 
 |       const TaskType task_type = | 
 |           incremental_marking->finalize_marking_completed() || | 
 |                   step_result != StepResult::kNoImmediateWork | 
 |               ? TaskType::kNormal | 
 |               : TaskType::kDelayed; | 
 |       job_->ScheduleTask(heap, task_type); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | double IncrementalMarkingJob::CurrentTimeToTask(Heap* heap) const { | 
 |   if (scheduled_time_ == 0.0) return 0.0; | 
 |  | 
 |   return heap->MonotonicallyIncreasingTimeInMs() - scheduled_time_; | 
 | } | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace v8 |