blob: 4bce0a4b61e209264ab9e7f2b77f7aa6b5decc96 [file] [log] [blame]
// Copyright 2018 The Chromium 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 "third_party/blink/renderer/platform/heap/unified_heap_controller.h"
#include "third_party/blink/renderer/platform/bindings/active_script_wrappable_base.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
#include "third_party/blink/renderer/platform/heap/marking_visitor.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
namespace blink {
namespace {
constexpr BlinkGC::StackState ToBlinkGCStackState(
v8::EmbedderHeapTracer::EmbedderStackState stack_state) {
return stack_state == v8::EmbedderHeapTracer::EmbedderStackState::kEmpty
? BlinkGC::kNoHeapPointersOnStack
: BlinkGC::kHeapPointersOnStack;
}
} // namespace
UnifiedHeapController::UnifiedHeapController(ThreadState* thread_state)
: thread_state_(thread_state) {}
void UnifiedHeapController::TracePrologue() {
VLOG(2) << "UnifiedHeapController::TracePrologue";
// Be conservative here as a new garbage collection gets started right away.
thread_state_->FinishIncrementalMarkingIfRunning(
BlinkGC::kHeapPointersOnStack, BlinkGC::kIncrementalMarking,
BlinkGC::kLazySweeping, thread_state_->current_gc_data_.reason);
// Reset any previously scheduled garbage collections.
thread_state_->SetGCState(ThreadState::kNoGCScheduled);
// Start incremental marking with unified tracing.
thread_state_->IncrementalMarkingStart(BlinkGC::GCReason::kUnifiedHeapGC);
is_tracing_done_ = false;
}
void UnifiedHeapController::EnterFinalPause(EmbedderStackState stack_state) {
VLOG(2) << "UnifiedHeapController::EnterFinalPause";
// ActiveScriptWrappable may not have persistents keeping them alive but rely
// on explicit tracing to be kept alive.
// TODO(mlippautz): Move to root scanning after stabilizing unified garbage
// collection.
ActiveScriptWrappableBase::TraceActiveScriptWrappables(
isolate_, thread_state_->CurrentVisitor());
thread_state_->EnterAtomicPause();
thread_state_->EnterGCForbiddenScope();
thread_state_->AtomicPauseMarkPrologue(ToBlinkGCStackState(stack_state),
BlinkGC::kIncrementalMarking,
BlinkGC::GCReason::kUnifiedHeapGC);
}
void UnifiedHeapController::TraceEpilogue() {
VLOG(2) << "UnifiedHeapController::TraceEpilogue";
thread_state_->AtomicPauseMarkEpilogue(BlinkGC::kIncrementalMarking);
thread_state_->LeaveAtomicPause();
thread_state_->LeaveGCForbiddenScope();
thread_state_->AtomicPauseSweepAndCompact(BlinkGC::kIncrementalMarking,
BlinkGC::kLazySweeping);
if (!thread_state_->IsSweepingInProgress()) {
// Sweeping was finished during the atomic pause. Update statistics needs to
// run outside of the top-most stats scope.
thread_state_->UpdateStatisticsAfterSweeping();
}
}
void UnifiedHeapController::RegisterV8References(
const std::vector<std::pair<void*, void*>>&
internal_fields_of_potential_wrappers) {
VLOG(2) << "UnifiedHeapController::RegisterV8References";
DCHECK(thread_state()->IsMarkingInProgress());
const bool was_in_atomic_pause = thread_state()->in_atomic_pause();
if (!was_in_atomic_pause)
ThreadState::Current()->EnterAtomicPause();
for (auto& internal_fields : internal_fields_of_potential_wrappers) {
WrapperTypeInfo* wrapper_type_info =
reinterpret_cast<WrapperTypeInfo*>(internal_fields.first);
if (wrapper_type_info->gin_embedder != gin::GinEmbedder::kEmbedderBlink) {
continue;
}
is_tracing_done_ = false;
wrapper_type_info->Trace(thread_state_->CurrentVisitor(),
internal_fields.second);
}
if (!was_in_atomic_pause)
ThreadState::Current()->LeaveAtomicPause();
}
bool UnifiedHeapController::AdvanceTracing(double deadline_in_ms) {
VLOG(2) << "UnifiedHeapController::AdvanceTracing";
if (!thread_state_->in_atomic_pause()) {
// V8 calls into embedder tracing from its own marking to ensure
// progress.Oilpan will additionally schedule marking steps.
ThreadState::AtomicPauseScope atomic_pause_scope(thread_state_);
TimeTicks deadline =
TimeTicks() + TimeDelta::FromMillisecondsD(deadline_in_ms);
is_tracing_done_ = thread_state_->MarkPhaseAdvanceMarking(deadline);
return is_tracing_done_;
}
thread_state_->AtomicPauseMarkTransitiveClosure();
is_tracing_done_ = true;
return true;
}
bool UnifiedHeapController::IsTracingDone() {
return is_tracing_done_;
}
} // namespace blink