// 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(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(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 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