11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/heap/cppgc/gc-invoker.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <memory>
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci#include "include/cppgc/common.h"
101cb0ef41Sopenharmony_ci#include "include/cppgc/platform.h"
111cb0ef41Sopenharmony_ci#include "src/heap/cppgc/heap.h"
121cb0ef41Sopenharmony_ci#include "src/heap/cppgc/task-handle.h"
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_cinamespace cppgc {
151cb0ef41Sopenharmony_cinamespace internal {
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciclass GCInvoker::GCInvokerImpl final : public GarbageCollector {
181cb0ef41Sopenharmony_ci public:
191cb0ef41Sopenharmony_ci  GCInvokerImpl(GarbageCollector*, cppgc::Platform*, cppgc::Heap::StackSupport);
201cb0ef41Sopenharmony_ci  ~GCInvokerImpl();
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci  GCInvokerImpl(const GCInvokerImpl&) = delete;
231cb0ef41Sopenharmony_ci  GCInvokerImpl& operator=(const GCInvokerImpl&) = delete;
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci  void CollectGarbage(GarbageCollector::Config) final;
261cb0ef41Sopenharmony_ci  void StartIncrementalGarbageCollection(GarbageCollector::Config) final;
271cb0ef41Sopenharmony_ci  size_t epoch() const final { return collector_->epoch(); }
281cb0ef41Sopenharmony_ci  const EmbedderStackState* override_stack_state() const final {
291cb0ef41Sopenharmony_ci    return collector_->override_stack_state();
301cb0ef41Sopenharmony_ci  }
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci private:
331cb0ef41Sopenharmony_ci  class GCTask final : public cppgc::Task {
341cb0ef41Sopenharmony_ci   public:
351cb0ef41Sopenharmony_ci    using Handle = SingleThreadedHandle;
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci    static Handle Post(GarbageCollector* collector, cppgc::TaskRunner* runner,
381cb0ef41Sopenharmony_ci                       GarbageCollector::Config config) {
391cb0ef41Sopenharmony_ci      auto task =
401cb0ef41Sopenharmony_ci          std::make_unique<GCInvoker::GCInvokerImpl::GCTask>(collector, config);
411cb0ef41Sopenharmony_ci      auto handle = task->GetHandle();
421cb0ef41Sopenharmony_ci      runner->PostNonNestableTask(std::move(task));
431cb0ef41Sopenharmony_ci      return handle;
441cb0ef41Sopenharmony_ci    }
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci    explicit GCTask(GarbageCollector* collector,
471cb0ef41Sopenharmony_ci                    GarbageCollector::Config config)
481cb0ef41Sopenharmony_ci        : collector_(collector),
491cb0ef41Sopenharmony_ci          config_(config),
501cb0ef41Sopenharmony_ci          handle_(Handle::NonEmptyTag{}),
511cb0ef41Sopenharmony_ci          saved_epoch_(collector->epoch()) {}
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci   private:
541cb0ef41Sopenharmony_ci    void Run() final {
551cb0ef41Sopenharmony_ci      CHECK_NULL(collector_->override_stack_state());
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci      if (handle_.IsCanceled() || (collector_->epoch() != saved_epoch_)) return;
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci      collector_->CollectGarbage(config_);
601cb0ef41Sopenharmony_ci      handle_.Cancel();
611cb0ef41Sopenharmony_ci    }
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci    Handle GetHandle() { return handle_; }
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci    GarbageCollector* collector_;
661cb0ef41Sopenharmony_ci    GarbageCollector::Config config_;
671cb0ef41Sopenharmony_ci    Handle handle_;
681cb0ef41Sopenharmony_ci    size_t saved_epoch_;
691cb0ef41Sopenharmony_ci  };
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  GarbageCollector* collector_;
721cb0ef41Sopenharmony_ci  cppgc::Platform* platform_;
731cb0ef41Sopenharmony_ci  cppgc::Heap::StackSupport stack_support_;
741cb0ef41Sopenharmony_ci  GCTask::Handle gc_task_handle_;
751cb0ef41Sopenharmony_ci};
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ciGCInvoker::GCInvokerImpl::GCInvokerImpl(GarbageCollector* collector,
781cb0ef41Sopenharmony_ci                                        cppgc::Platform* platform,
791cb0ef41Sopenharmony_ci                                        cppgc::Heap::StackSupport stack_support)
801cb0ef41Sopenharmony_ci    : collector_(collector),
811cb0ef41Sopenharmony_ci      platform_(platform),
821cb0ef41Sopenharmony_ci      stack_support_(stack_support) {}
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ciGCInvoker::GCInvokerImpl::~GCInvokerImpl() {
851cb0ef41Sopenharmony_ci  if (gc_task_handle_) {
861cb0ef41Sopenharmony_ci    gc_task_handle_.Cancel();
871cb0ef41Sopenharmony_ci  }
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_civoid GCInvoker::GCInvokerImpl::CollectGarbage(GarbageCollector::Config config) {
911cb0ef41Sopenharmony_ci  DCHECK_EQ(config.marking_type, cppgc::Heap::MarkingType::kAtomic);
921cb0ef41Sopenharmony_ci  if ((config.stack_state ==
931cb0ef41Sopenharmony_ci       GarbageCollector::Config::StackState::kNoHeapPointers) ||
941cb0ef41Sopenharmony_ci      (stack_support_ ==
951cb0ef41Sopenharmony_ci       cppgc::Heap::StackSupport::kSupportsConservativeStackScan)) {
961cb0ef41Sopenharmony_ci    collector_->CollectGarbage(config);
971cb0ef41Sopenharmony_ci  } else if (platform_->GetForegroundTaskRunner() &&
981cb0ef41Sopenharmony_ci             platform_->GetForegroundTaskRunner()->NonNestableTasksEnabled()) {
991cb0ef41Sopenharmony_ci    if (!gc_task_handle_) {
1001cb0ef41Sopenharmony_ci      // Force a precise GC since it will run in a non-nestable task.
1011cb0ef41Sopenharmony_ci      config.stack_state =
1021cb0ef41Sopenharmony_ci          GarbageCollector::Config::StackState::kNoHeapPointers;
1031cb0ef41Sopenharmony_ci      DCHECK_NE(cppgc::Heap::StackSupport::kSupportsConservativeStackScan,
1041cb0ef41Sopenharmony_ci                stack_support_);
1051cb0ef41Sopenharmony_ci      gc_task_handle_ = GCTask::Post(
1061cb0ef41Sopenharmony_ci          collector_, platform_->GetForegroundTaskRunner().get(), config);
1071cb0ef41Sopenharmony_ci    }
1081cb0ef41Sopenharmony_ci  }
1091cb0ef41Sopenharmony_ci}
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_civoid GCInvoker::GCInvokerImpl::StartIncrementalGarbageCollection(
1121cb0ef41Sopenharmony_ci    GarbageCollector::Config config) {
1131cb0ef41Sopenharmony_ci  DCHECK_NE(config.marking_type, cppgc::Heap::MarkingType::kAtomic);
1141cb0ef41Sopenharmony_ci  if ((stack_support_ !=
1151cb0ef41Sopenharmony_ci       cppgc::Heap::StackSupport::kSupportsConservativeStackScan) &&
1161cb0ef41Sopenharmony_ci      (!platform_->GetForegroundTaskRunner() ||
1171cb0ef41Sopenharmony_ci       !platform_->GetForegroundTaskRunner()->NonNestableTasksEnabled())) {
1181cb0ef41Sopenharmony_ci    // In this configuration the GC finalization can only be triggered through
1191cb0ef41Sopenharmony_ci    // ForceGarbageCollectionSlow. If incremental GC is started, there is no
1201cb0ef41Sopenharmony_ci    // way to know how long it will remain enabled (and the write barrier with
1211cb0ef41Sopenharmony_ci    // it). For that reason, we do not support running incremental GCs in this
1221cb0ef41Sopenharmony_ci    // configuration.
1231cb0ef41Sopenharmony_ci    return;
1241cb0ef41Sopenharmony_ci  }
1251cb0ef41Sopenharmony_ci  // No need to postpone starting incremental GC since the stack is not scanned
1261cb0ef41Sopenharmony_ci  // until GC finalization.
1271cb0ef41Sopenharmony_ci  collector_->StartIncrementalGarbageCollection(config);
1281cb0ef41Sopenharmony_ci}
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ciGCInvoker::GCInvoker(GarbageCollector* collector, cppgc::Platform* platform,
1311cb0ef41Sopenharmony_ci                     cppgc::Heap::StackSupport stack_support)
1321cb0ef41Sopenharmony_ci    : impl_(std::make_unique<GCInvoker::GCInvokerImpl>(collector, platform,
1331cb0ef41Sopenharmony_ci                                                       stack_support)) {}
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ciGCInvoker::~GCInvoker() = default;
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_civoid GCInvoker::CollectGarbage(GarbageCollector::Config config) {
1381cb0ef41Sopenharmony_ci  impl_->CollectGarbage(config);
1391cb0ef41Sopenharmony_ci}
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_civoid GCInvoker::StartIncrementalGarbageCollection(
1421cb0ef41Sopenharmony_ci    GarbageCollector::Config config) {
1431cb0ef41Sopenharmony_ci  impl_->StartIncrementalGarbageCollection(config);
1441cb0ef41Sopenharmony_ci}
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_cisize_t GCInvoker::epoch() const { return impl_->epoch(); }
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ciconst EmbedderStackState* GCInvoker::override_stack_state() const {
1491cb0ef41Sopenharmony_ci  return impl_->override_stack_state();
1501cb0ef41Sopenharmony_ci}
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci}  // namespace internal
1531cb0ef41Sopenharmony_ci}  // namespace cppgc
154