diff --git a/BUILD.gn b/BUILD.gn index 5d9db13bb0..4930e7025a 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -4374,8 +4374,6 @@ v8_source_set("cppgc_base") { "src/heap/cppgc/allocation.cc", "src/heap/cppgc/concurrent-marker.cc", "src/heap/cppgc/concurrent-marker.h", - "src/heap/cppgc/default-job.h", - "src/heap/cppgc/default-platform.cc", "src/heap/cppgc/free-list.cc", "src/heap/cppgc/free-list.h", "src/heap/cppgc/garbage-collector.h", @@ -4457,6 +4455,7 @@ v8_source_set("cppgc_base") { public_deps = [ ":v8_cppgc_shared", ":v8_libbase", + ":v8_libplatform", ] } diff --git a/include/cppgc/DEPS b/include/cppgc/DEPS index 04c343de27..861d1187ba 100644 --- a/include/cppgc/DEPS +++ b/include/cppgc/DEPS @@ -4,4 +4,5 @@ include_rules = [ "+v8-platform.h", "+cppgc", "-src", + "+libplatform/libplatform.h", ] diff --git a/include/cppgc/default-platform.h b/include/cppgc/default-platform.h index da8129a81b..be83738b41 100644 --- a/include/cppgc/default-platform.h +++ b/include/cppgc/default-platform.h @@ -9,74 +9,49 @@ #include #include "cppgc/platform.h" +#include "libplatform/libplatform.h" #include "v8config.h" // NOLINT(build/include_directory) namespace cppgc { -namespace internal { -class DefaultJob; -} // namespace internal - /** - * Default task runner implementation. Keep posted tasks in a list that can be - * processed by calling RunSingleTask() or RunUntilIdle(). + * Platform provided by cppgc. Uses V8's DefaultPlatform provided by + * libplatform internally.Exception: GetForegroundTaskRunner(), see below. */ -class V8_EXPORT DefaultTaskRunner final : public cppgc::TaskRunner { +class V8_EXPORT DefaultPlatform : public Platform { public: - DefaultTaskRunner() = default; + using IdleTaskSupport = v8::platform::IdleTaskSupport; + explicit DefaultPlatform( + int thread_pool_size = 0, + IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled) + : v8_platform_(v8::platform::NewDefaultPlatform(thread_pool_size, + idle_task_support)) {} - DefaultTaskRunner(const DefaultTaskRunner&) = delete; - DefaultTaskRunner& operator=(const DefaultTaskRunner&) = delete; + cppgc::PageAllocator* GetPageAllocator() override { + return v8_platform_->GetPageAllocator(); + } - void PostTask(std::unique_ptr task) override; - void PostDelayedTask(std::unique_ptr task, double) override; + double MonotonicallyIncreasingTime() override { + return v8_platform_->MonotonicallyIncreasingTime(); + } - bool NonNestableTasksEnabled() const final { return false; } - bool NonNestableDelayedTasksEnabled() const final { return false; } - void PostNonNestableTask(std::unique_ptr task) override; - void PostNonNestableDelayedTask(std::unique_ptr task, - double) override; + std::shared_ptr GetForegroundTaskRunner() override { + // V8's default platform creates a new task runner when passed the + // v8::Isolate pointer the first time. For non-default platforms this will + // require getting the appropriate task runner. + return v8_platform_->GetForegroundTaskRunner(kNoIsolate); + } - void PostIdleTask(std::unique_ptr task) override; - bool IdleTasksEnabled() override { return true; } - - bool RunSingleTask(); - bool RunSingleIdleTask(double duration_in_seconds); - - void RunUntilIdle(); - - private: - std::vector> tasks_; - std::vector> idle_tasks_; -}; - -/** - * Default platform implementation that uses std::thread for spawning job tasks. - */ -class V8_EXPORT DefaultPlatform final : public Platform { - public: - DefaultPlatform(); - ~DefaultPlatform() noexcept override; - - cppgc::PageAllocator* GetPageAllocator() final; - - double MonotonicallyIncreasingTime() final; - - std::shared_ptr GetForegroundTaskRunner() final; - - // DefaultPlatform does not support job priorities. All jobs would be - // assigned the same priority regardless of the cppgc::TaskPriority parameter. std::unique_ptr PostJob( cppgc::TaskPriority priority, - std::unique_ptr job_task) final; + std::unique_ptr job_task) override { + return v8_platform_->PostJob(priority, std::move(job_task)); + } - void WaitAllForegroundTasks(); - void WaitAllBackgroundTasks(); + protected: + static constexpr v8::Isolate* kNoIsolate = nullptr; - private: - std::unique_ptr page_allocator_; - std::shared_ptr foreground_task_runner_; - std::vector> jobs_; + std::unique_ptr v8_platform_; }; } // namespace cppgc diff --git a/samples/cppgc/cppgc-for-v8-embedders.cc b/samples/cppgc/cppgc-for-v8-embedders.cc index 8aaa9cd39c..b4d7ed9e4d 100644 --- a/samples/cppgc/cppgc-for-v8-embedders.cc +++ b/samples/cppgc/cppgc-for-v8-embedders.cc @@ -3,12 +3,12 @@ // found in the LICENSE file. #include +#include #include #include #include #include #include -#include #include #include @@ -21,42 +21,6 @@ * platform for cppgc. */ -/** - * Platform used by cppgc. Can just redirect to v8::Platform for most calls. - * Exception: GetForegroundTaskRunner(), see below. - * - * This example uses V8's default platform implementation to drive the cppgc - * platform. - */ -class Platform final : public cppgc::Platform { - public: - Platform() : v8_platform_(v8::platform::NewDefaultPlatform()) {} - - cppgc::PageAllocator* GetPageAllocator() final { - return v8_platform_->GetPageAllocator(); - } - - double MonotonicallyIncreasingTime() final { - return v8_platform_->MonotonicallyIncreasingTime(); - } - - std::shared_ptr GetForegroundTaskRunner() final { - // V8's default platform creates a new task runner when passed the - // v8::Isolate pointer the first time. For non-default platforms this will - // require getting the appropriate task runner. - return v8_platform_->GetForegroundTaskRunner(nullptr); - } - - std::unique_ptr PostJob( - cppgc::TaskPriority priority, - std::unique_ptr job_task) final { - return v8_platform_->PostJob(priority, std::move(job_task)); - } - - private: - std::unique_ptr v8_platform_; -}; - /** * Simple string rope to illustrate allocation and garbage collection below. The * rope keeps the next parts alive via regular managed reference. @@ -86,7 +50,7 @@ std::ostream& operator<<(std::ostream& os, const Rope& rope) { int main(int argc, char* argv[]) { // Create a platform that is used by cppgc::Heap for execution and backend // allocation. - auto cppgc_platform = std::make_shared(); + auto cppgc_platform = std::make_shared(); // Initialize the process. This must happen before any cppgc::Heap::Create() // calls. cppgc::InitializeProcess(cppgc_platform->GetPageAllocator()); diff --git a/src/heap/cppgc/concurrent-marker.cc b/src/heap/cppgc/concurrent-marker.cc index c1a84169b3..ab2ab81842 100644 --- a/src/heap/cppgc/concurrent-marker.cc +++ b/src/heap/cppgc/concurrent-marker.cc @@ -161,7 +161,7 @@ ConcurrentMarkerBase::ConcurrentMarkerBase( platform_(platform) {} void ConcurrentMarkerBase::Start() { - if (!platform_) return; + DCHECK(platform_); concurrent_marking_handle_ = platform_->PostJob(v8::TaskPriority::kUserVisible, std::make_unique(*this)); diff --git a/src/heap/cppgc/default-job.h b/src/heap/cppgc/default-job.h deleted file mode 100644 index 0ea1fa1c59..0000000000 --- a/src/heap/cppgc/default-job.h +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2020 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. - -#ifndef V8_HEAP_CPPGC_DEFAULT_JOB_H_ -#define V8_HEAP_CPPGC_DEFAULT_JOB_H_ - -#include -#include -#include -#include -#include - -#include "include/cppgc/platform.h" -#include "src/base/logging.h" -#include "src/base/platform/mutex.h" - -namespace cppgc { -namespace internal { - -template -class DefaultJobFactory { - public: - static std::shared_ptr Create(std::unique_ptr job_task) { - std::shared_ptr job = - std::make_shared(typename Job::Key(), std::move(job_task)); - job->NotifyConcurrencyIncrease(); - return job; - } -}; - -template -class DefaultJobImpl { - public: - class JobDelegate; - class JobHandle; - - class Key { - private: - Key() {} - - template - friend class DefaultJobFactory; - }; - - DefaultJobImpl(Key, std::unique_ptr job_task) - : job_task_(std::move(job_task)) {} - - ~DefaultJobImpl() { - Cancel(); - DCHECK_EQ(0, active_threads_.load(std::memory_order_relaxed)); - } - - void NotifyConcurrencyIncrease(); - - void Join() { - for (std::shared_ptr& thread : job_threads_) thread->Join(); - job_threads_.clear(); - can_run_.store(false, std::memory_order_relaxed); - } - - void Cancel() { - can_run_.store(false, std::memory_order_relaxed); - Join(); - } - - void CancelAndDetach() { can_run_.store(false, std::memory_order_relaxed); } - - bool IsCompleted() const { return !IsRunning(); } - bool IsRunning() const { - uint8_t active_threads = active_threads_.load(std::memory_order_relaxed); - return (active_threads + job_task_->GetMaxConcurrency(active_threads)) > 0; - } - - bool CanRun() const { return can_run_.load(std::memory_order_relaxed); } - - void RunJobTask() { - DCHECK_NOT_NULL(job_task_); - NotifyJobThreadStart(); - JobDelegate delegate(this); - job_task_->Run(&delegate); - NotifyJobThreadEnd(); - } - - protected: - virtual std::shared_ptr CreateThread(DefaultJobImpl*) = 0; - - void NotifyJobThreadStart() { - active_threads_.fetch_add(1, std::memory_order_relaxed); - } - void NotifyJobThreadEnd() { - active_threads_.fetch_sub(1, std::memory_order_relaxed); - } - - void GuaranteeAvailableIds(uint8_t max_threads) { - if (max_threads <= highest_thread_count_) return; - v8::base::MutexGuard guard(&ids_lock_); - while (highest_thread_count_ < max_threads) { - available_ids_.push_back(++highest_thread_count_); - } - } - - std::unique_ptr job_task_; - std::vector> job_threads_; - std::atomic_bool can_run_{true}; - std::atomic active_threads_{0}; - - // Task id management. - v8::base::Mutex ids_lock_; - std::vector available_ids_; - uint8_t highest_thread_count_ = -1; -}; - -template -class DefaultJobImpl::JobDelegate final : public cppgc::JobDelegate { - public: - explicit JobDelegate(DefaultJobImpl* job) : job_(job) {} - ~JobDelegate() { ReleaseTaskId(); } - bool ShouldYield() override { return !job_->CanRun(); } - void NotifyConcurrencyIncrease() override { - job_->NotifyConcurrencyIncrease(); - } - uint8_t GetTaskId() override { - AcquireTaskId(); - return job_thread_id_; - } - - private: - void AcquireTaskId() { - if (job_thread_id_ != kInvalidTaskId) return; - v8::base::MutexGuard guard(&job_->ids_lock_); - job_thread_id_ = job_->available_ids_.back(); - DCHECK_NE(kInvalidTaskId, job_thread_id_); - job_->available_ids_.pop_back(); - } - void ReleaseTaskId() { - if (job_thread_id_ == kInvalidTaskId) return; - v8::base::MutexGuard guard(&job_->ids_lock_); - job_->available_ids_.push_back(job_thread_id_); - } - - DefaultJobImpl* const job_; - static constexpr uint8_t kInvalidTaskId = std::numeric_limits::max(); - uint8_t job_thread_id_ = kInvalidTaskId; -}; - -template -void DefaultJobImpl::NotifyConcurrencyIncrease() { - DCHECK(CanRun()); - static const size_t kMaxThreads = Thread::GetMaxSupportedConcurrency(); - uint8_t current_active_threads = - active_threads_.load(std::memory_order_relaxed); - size_t max_threads = std::min( - kMaxThreads, job_task_->GetMaxConcurrency(current_active_threads)); - if (current_active_threads >= max_threads) return; - DCHECK_LT(max_threads, std::numeric_limits::max()); - GuaranteeAvailableIds(max_threads); - for (uint8_t new_threads = max_threads - current_active_threads; - new_threads > 0; --new_threads) { - std::shared_ptr thread = CreateThread(this); - job_threads_.push_back(thread); - } -} - -template -class DefaultJobImpl::JobHandle final : public cppgc::JobHandle { - public: - explicit JobHandle(std::shared_ptr job) - : job_(std::move(job)) { - DCHECK_NOT_NULL(job_); - } - - void NotifyConcurrencyIncrease() override { - job_->NotifyConcurrencyIncrease(); - } - void Join() override { job_->Join(); } - void Cancel() override { job_->Cancel(); } - void CancelAndDetach() override { job_->CancelAndDetach(); } - bool IsCompleted() override { return job_->IsCompleted(); } - bool IsRunning() override { return job_->IsRunning(); } - - // DefaultJobImpl doesn't support priorities. - bool UpdatePriorityEnabled() const override { return false; } - void UpdatePriority(TaskPriority) override { UNREACHABLE(); } - - private: - std::shared_ptr job_; -}; - -} // namespace internal -} // namespace cppgc - -#endif // V8_HEAP_CPPGC_DEFAULT_JOB_H_ diff --git a/src/heap/cppgc/default-platform.cc b/src/heap/cppgc/default-platform.cc deleted file mode 100644 index 0ac5440f7e..0000000000 --- a/src/heap/cppgc/default-platform.cc +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2020 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 "include/cppgc/default-platform.h" - -#include // NOLINT(build/c++11) -#include // NOLINT(build/c++11) - -#include "src/base/logging.h" -#include "src/base/page-allocator.h" -#include "src/base/sys-info.h" -#include "src/heap/cppgc/default-job.h" - -namespace cppgc { - -namespace internal { - -// Default implementation of Jobs based on std::thread. -namespace { -class DefaultJobThread final : private std::thread { - public: - template - explicit DefaultJobThread(Function function) - : std::thread(std::move(function)) {} - ~DefaultJobThread() { DCHECK(!joinable()); } - - void Join() { join(); } - - static size_t GetMaxSupportedConcurrency() { - return v8::base::SysInfo::NumberOfProcessors() - 1; - } -}; -} // namespace - -class DefaultJob final : public DefaultJobImpl { - public: - DefaultJob(Key key, std::unique_ptr job_task) - : DefaultJobImpl(key, std::move(job_task)) {} - - std::shared_ptr CreateThread(DefaultJobImpl* job) final { - return std::make_shared([job = this] { - DCHECK_NOT_NULL(job); - job->RunJobTask(); - }); - } -}; - -} // namespace internal - -void DefaultTaskRunner::PostTask(std::unique_ptr task) { - tasks_.push_back(std::move(task)); -} - -void DefaultTaskRunner::PostDelayedTask(std::unique_ptr task, - double) { - PostTask(std::move(task)); -} - -void DefaultTaskRunner::PostNonNestableTask(std::unique_ptr) { - UNREACHABLE(); -} - -void DefaultTaskRunner::PostNonNestableDelayedTask(std::unique_ptr, - double) { - UNREACHABLE(); -} - -void DefaultTaskRunner::PostIdleTask(std::unique_ptr task) { - idle_tasks_.push_back(std::move(task)); -} - -bool DefaultTaskRunner::RunSingleTask() { - if (!tasks_.size()) return false; - - tasks_.back()->Run(); - tasks_.pop_back(); - - return true; -} - -bool DefaultTaskRunner::RunSingleIdleTask(double deadline_in_seconds) { - if (!idle_tasks_.size()) return false; - - idle_tasks_.back()->Run(deadline_in_seconds); - idle_tasks_.pop_back(); - - return true; -} - -void DefaultTaskRunner::RunUntilIdle() { - for (auto& task : tasks_) { - task->Run(); - } - tasks_.clear(); - - for (auto& task : idle_tasks_) { - task->Run(std::numeric_limits::infinity()); - } - idle_tasks_.clear(); -} - -DefaultPlatform::DefaultPlatform() - : page_allocator_(std::make_unique()), - foreground_task_runner_(std::make_shared()) {} - -DefaultPlatform::~DefaultPlatform() noexcept { WaitAllBackgroundTasks(); } - -cppgc::PageAllocator* DefaultPlatform::GetPageAllocator() { - return page_allocator_.get(); -} - -double DefaultPlatform::MonotonicallyIncreasingTime() { - return std::chrono::duration( - std::chrono::high_resolution_clock::now().time_since_epoch()) - .count(); -} - -std::shared_ptr DefaultPlatform::GetForegroundTaskRunner() { - return foreground_task_runner_; -} - -std::unique_ptr DefaultPlatform::PostJob( - cppgc::TaskPriority priority, std::unique_ptr job_task) { - std::shared_ptr job = - internal::DefaultJobFactory::Create( - std::move(job_task)); - jobs_.push_back(job); - return std::make_unique(std::move(job)); -} - -void DefaultPlatform::WaitAllForegroundTasks() { - foreground_task_runner_->RunUntilIdle(); -} - -void DefaultPlatform::WaitAllBackgroundTasks() { - for (auto& job : jobs_) { - job->Join(); - } - jobs_.clear(); -} - -} // namespace cppgc diff --git a/src/heap/cppgc/marker.cc b/src/heap/cppgc/marker.cc index 854289c0d9..5f56d79bba 100644 --- a/src/heap/cppgc/marker.cc +++ b/src/heap/cppgc/marker.cc @@ -261,8 +261,8 @@ void MarkerBase::VisitRoots(MarkingConfig::StackState stack_state) { } void MarkerBase::ScheduleIncrementalMarkingTask() { - if (!platform_ || !foreground_task_runner_ || incremental_marking_handle_) - return; + DCHECK(platform_); + if (!foreground_task_runner_ || incremental_marking_handle_) return; incremental_marking_handle_ = IncrementalMarkingTask::Post(foreground_task_runner_.get(), this); } diff --git a/src/heap/cppgc/sweeper.cc b/src/heap/cppgc/sweeper.cc index 27d4e7b3a4..e9b9cb9049 100644 --- a/src/heap/cppgc/sweeper.cc +++ b/src/heap/cppgc/sweeper.cc @@ -504,13 +504,11 @@ class Sweeper::SweeperImpl final { void FinishIfRunning() { if (!is_in_progress_) return; - if (concurrent_sweeper_handle_ && + if (concurrent_sweeper_handle_ && concurrent_sweeper_handle_->IsRunning() && concurrent_sweeper_handle_->UpdatePriorityEnabled()) { - DCHECK(concurrent_sweeper_handle_->IsRunning()); concurrent_sweeper_handle_->UpdatePriority( cppgc::TaskPriority::kUserBlocking); } - Finish(); } @@ -533,6 +531,10 @@ class Sweeper::SweeperImpl final { stats_collector_->NotifySweepingCompleted(); } + void WaitForConcurrentSweepingForTesting() { + if (concurrent_sweeper_handle_) concurrent_sweeper_handle_->Join(); + } + private: class IncrementalSweepTask : public cppgc::IdleTask { public: @@ -572,14 +574,17 @@ class Sweeper::SweeperImpl final { }; void ScheduleIncrementalSweeping() { - if (!platform_ || !foreground_task_runner_) return; + DCHECK(platform_); + if (!foreground_task_runner_ || + !foreground_task_runner_->IdleTasksEnabled()) + return; incremental_sweeper_handle_ = IncrementalSweepTask::Post(this, foreground_task_runner_.get()); } void ScheduleConcurrentSweeping() { - if (!platform_) return; + DCHECK(platform_); concurrent_sweeper_handle_ = platform_->PostJob( cppgc::TaskPriority::kUserVisible, @@ -588,7 +593,8 @@ class Sweeper::SweeperImpl final { void CancelSweepers() { if (incremental_sweeper_handle_) incremental_sweeper_handle_.Cancel(); - if (concurrent_sweeper_handle_) concurrent_sweeper_handle_->Cancel(); + if (concurrent_sweeper_handle_ && concurrent_sweeper_handle_->IsRunning()) + concurrent_sweeper_handle_->Cancel(); } void SynchronizeAndFinalizeConcurrentSweeping() { @@ -616,6 +622,9 @@ Sweeper::~Sweeper() = default; void Sweeper::Start(Config config) { impl_->Start(config); } void Sweeper::FinishIfRunning() { impl_->FinishIfRunning(); } +void Sweeper::WaitForConcurrentSweepingForTesting() { + impl_->WaitForConcurrentSweepingForTesting(); +} } // namespace internal } // namespace cppgc diff --git a/src/heap/cppgc/sweeper.h b/src/heap/cppgc/sweeper.h index e94036521e..b8fc4b2078 100644 --- a/src/heap/cppgc/sweeper.h +++ b/src/heap/cppgc/sweeper.h @@ -17,6 +17,7 @@ namespace internal { class StatsCollector; class RawHeap; +class ConcurrentSweeperTest; class V8_EXPORT_PRIVATE Sweeper final { public: @@ -33,8 +34,12 @@ class V8_EXPORT_PRIVATE Sweeper final { void FinishIfRunning(); private: + void WaitForConcurrentSweepingForTesting(); + class SweeperImpl; std::unique_ptr impl_; + + friend class ConcurrentSweeperTest; }; } // namespace internal diff --git a/test/unittests/heap/cppgc/concurrent-sweeper-unittest.cc b/test/unittests/heap/cppgc/concurrent-sweeper-unittest.cc index 3794adce25..27a4be0041 100644 --- a/test/unittests/heap/cppgc/concurrent-sweeper-unittest.cc +++ b/test/unittests/heap/cppgc/concurrent-sweeper-unittest.cc @@ -61,6 +61,8 @@ class NonFinalizable : public GarbageCollected> { using NormalNonFinalizable = NonFinalizable<32>; using LargeNonFinalizable = NonFinalizable; +} // namespace + class ConcurrentSweeperTest : public testing::TestWithHeap { public: ConcurrentSweeperTest() { g_destructor_callcount = 0; } @@ -76,6 +78,12 @@ class ConcurrentSweeperTest : public testing::TestWithHeap { sweeper.Start(Sweeper::Config::kIncrementalAndConcurrent); } + void WaitForConcurrentSweeping() { + Heap* heap = Heap::From(GetHeap()); + Sweeper& sweeper = heap->sweeper(); + sweeper.WaitForConcurrentSweepingForTesting(); + } + void FinishSweeping() { Heap* heap = Heap::From(GetHeap()); Sweeper& sweeper = heap->sweeper(); @@ -126,8 +134,6 @@ class ConcurrentSweeperTest : public testing::TestWithHeap { } }; -} // namespace - TEST_F(ConcurrentSweeperTest, BackgroundSweepOfNormalPage) { // Non finalizable objects are swept right away. using GCedType = NormalNonFinalizable; @@ -145,7 +151,7 @@ TEST_F(ConcurrentSweeperTest, BackgroundSweepOfNormalPage) { StartSweeping(); // Wait for concurrent sweeping to finish. - GetPlatform().WaitAllBackgroundTasks(); + WaitForConcurrentSweeping(); #if !defined(CPPGC_YOUNG_GENERATION) // Check that the marked object was unmarked. @@ -184,7 +190,7 @@ TEST_F(ConcurrentSweeperTest, BackgroundSweepOfLargePage) { StartSweeping(); // Wait for concurrent sweeping to finish. - GetPlatform().WaitAllBackgroundTasks(); + WaitForConcurrentSweeping(); #if !defined(CPPGC_YOUNG_GENERATION) // Check that the marked object was unmarked. @@ -224,7 +230,7 @@ TEST_F(ConcurrentSweeperTest, DeferredFinalizationOfNormalPage) { StartSweeping(); // Wait for concurrent sweeping to finish. - GetPlatform().WaitAllBackgroundTasks(); + WaitForConcurrentSweeping(); // Check that pages are not returned right away. for (auto* page : pages) { @@ -256,7 +262,7 @@ TEST_F(ConcurrentSweeperTest, DeferredFinalizationOfLargePage) { StartSweeping(); // Wait for concurrent sweeping to finish. - GetPlatform().WaitAllBackgroundTasks(); + WaitForConcurrentSweeping(); // Check that the page is not returned to the space. EXPECT_EQ(space->end(), std::find(space->begin(), space->end(), page)); @@ -302,7 +308,7 @@ TEST_F(ConcurrentSweeperTest, IncrementalSweeping) { EXPECT_TRUE(marked_large_header.IsMarked()); // Wait for incremental sweeper to finish. - GetPlatform().WaitAllForegroundTasks(); + GetPlatform().RunAllForegroundTasks(); EXPECT_EQ(2u, g_destructor_callcount); #if !defined(CPPGC_YOUNG_GENERATION) diff --git a/test/unittests/heap/cppgc/gc-invoker-unittest.cc b/test/unittests/heap/cppgc/gc-invoker-unittest.cc index 9dc1b8d426..319f6e433d 100644 --- a/test/unittests/heap/cppgc/gc-invoker-unittest.cc +++ b/test/unittests/heap/cppgc/gc-invoker-unittest.cc @@ -105,7 +105,7 @@ TEST(GCInvokerTest, ConservativeGCIsInvokedAsPreciseGCViaPlatform) { EXPECT_CALL(gc, epoch).WillRepeatedly(::testing::Return(0)); EXPECT_CALL(gc, CollectGarbage); invoker.CollectGarbage(GarbageCollector::Config::ConservativeAtomicConfig()); - platform.WaitAllForegroundTasks(); + platform.RunAllForegroundTasks(); } TEST(GCInvokerTest, IncrementalGCIsStarted) { diff --git a/test/unittests/heap/cppgc/test-platform.cc b/test/unittests/heap/cppgc/test-platform.cc index c649b1e89d..2268d546b3 100644 --- a/test/unittests/heap/cppgc/test-platform.cc +++ b/test/unittests/heap/cppgc/test-platform.cc @@ -4,132 +4,29 @@ #include "test/unittests/heap/cppgc/test-platform.h" +#include "include/libplatform/libplatform.h" #include "src/base/platform/platform.h" #include "src/base/platform/time.h" -#include "src/heap/cppgc/default-job.h" namespace cppgc { namespace internal { namespace testing { -namespace { -class TestJobThread final : public v8::base::Thread { - public: - using id = uint8_t; - - explicit TestJobThread(TestJob* job) : Thread(Options("job")), job_(job) {} - - void Run() final; - - static size_t GetMaxSupportedConcurrency() { return 4u; } - - private: - TestJob* const job_; -}; -} // namespace - -// Default implementation of Jobs based on std::thread. -class TestJob final : public DefaultJobImpl { - public: - explicit TestJob(Key key, std::unique_ptr job_task) - : DefaultJobImpl(key, std::move(job_task)) {} - - std::shared_ptr CreateThread(DefaultJobImpl* job) final { - std::shared_ptr thread = - std::make_shared(this); - const bool thread_started = thread->Start(); - USE(thread_started); - DCHECK(thread_started); - return thread; - } -}; - -void TestJobThread::Run() { - DCHECK_NOT_NULL(job_); - job_->RunJobTask(); -} - -void TestTaskRunner::PostTask(std::unique_ptr task) { - tasks_.push_back(std::move(task)); -} - -void TestTaskRunner::PostNonNestableTask(std::unique_ptr task) { - PostTask(std::move(task)); -} - -void TestTaskRunner::PostDelayedTask(std::unique_ptr task, - double) { - PostTask(std::move(task)); -} - -void TestTaskRunner::PostNonNestableDelayedTask( - std::unique_ptr task, double) { - PostTask(std::move(task)); -} - -void TestTaskRunner::PostIdleTask(std::unique_ptr task) { - idle_tasks_.push_back(std::move(task)); -} - -bool TestTaskRunner::RunSingleTask() { - if (!tasks_.size()) return false; - - tasks_.back()->Run(); - tasks_.pop_back(); - - return true; -} - -bool TestTaskRunner::RunSingleIdleTask(double deadline_in_seconds) { - if (!idle_tasks_.size()) return false; - - idle_tasks_.back()->Run(deadline_in_seconds); - idle_tasks_.pop_back(); - - return true; -} - -void TestTaskRunner::RunUntilIdle() { - for (auto& task : tasks_) { - task->Run(); - } - tasks_.clear(); - - for (auto& task : idle_tasks_) { - task->Run(std::numeric_limits::infinity()); - } - idle_tasks_.clear(); -} - TestPlatform::TestPlatform() - : foreground_task_runner_(std::make_unique()) {} - -TestPlatform::~TestPlatform() V8_NOEXCEPT { WaitAllBackgroundTasks(); } + : DefaultPlatform(0, DefaultPlatform::IdleTaskSupport::kEnabled) {} std::unique_ptr TestPlatform::PostJob( - cppgc::TaskPriority, std::unique_ptr job_task) { - if (AreBackgroundTasksDisabled()) return {}; - - std::shared_ptr job = - DefaultJobFactory::Create(std::move(job_task)); - jobs_.push_back(job); - return std::make_unique(std::move(job)); + cppgc::TaskPriority priority, std::unique_ptr job_task) { + if (AreBackgroundTasksDisabled()) return nullptr; + return v8_platform_->PostJob(priority, std::move(job_task)); } -double TestPlatform::MonotonicallyIncreasingTime() { - return v8::base::TimeTicks::HighResolutionNow().ToInternalValue() / - static_cast(v8::base::Time::kMicrosecondsPerSecond); -} - -void TestPlatform::WaitAllForegroundTasks() { - foreground_task_runner_->RunUntilIdle(); -} - -void TestPlatform::WaitAllBackgroundTasks() { - for (auto& job : jobs_) { - job->Join(); +void TestPlatform::RunAllForegroundTasks() { + v8::platform::PumpMessageLoop(v8_platform_.get(), kNoIsolate); + if (GetForegroundTaskRunner()->IdleTasksEnabled()) { + v8::platform::RunIdleTasks(v8_platform_.get(), kNoIsolate, + std::numeric_limits::max()); } - jobs_.clear(); } TestPlatform::DisableBackgroundTasksScope::DisableBackgroundTasksScope( diff --git a/test/unittests/heap/cppgc/test-platform.h b/test/unittests/heap/cppgc/test-platform.h index 1faa6efb40..d6a93f45c9 100644 --- a/test/unittests/heap/cppgc/test-platform.h +++ b/test/unittests/heap/cppgc/test-platform.h @@ -5,45 +5,14 @@ #ifndef V8_UNITTESTS_HEAP_CPPGC_TEST_PLATFORM_H_ #define V8_UNITTESTS_HEAP_CPPGC_TEST_PLATFORM_H_ -#include -#include - -#include "include/cppgc/platform.h" -#include "src/base/page-allocator.h" -#include "src/base/platform/platform.h" +#include "include/cppgc/default-platform.h" +#include "src/base/compiler-specific.h" namespace cppgc { namespace internal { namespace testing { -class TestJob; - -class TestTaskRunner : public cppgc::TaskRunner { - public: - void PostTask(std::unique_ptr task) override; - void PostDelayedTask(std::unique_ptr task, double) override; - - bool NonNestableTasksEnabled() const override { return true; } - void PostNonNestableTask(std::unique_ptr task) override; - - bool NonNestableDelayedTasksEnabled() const override { return true; } - void PostNonNestableDelayedTask(std::unique_ptr task, - double) override; - - bool IdleTasksEnabled() override { return true; } - void PostIdleTask(std::unique_ptr task) override; - - bool RunSingleTask(); - bool RunSingleIdleTask(double duration_in_seconds); - - void RunUntilIdle(); - - private: - std::vector> tasks_; - std::vector> idle_tasks_; -}; - -class TestPlatform : public Platform { +class TestPlatform : public DefaultPlatform { public: class DisableBackgroundTasksScope { public: @@ -55,32 +24,18 @@ class TestPlatform : public Platform { }; TestPlatform(); - ~TestPlatform() V8_NOEXCEPT override; - PageAllocator* GetPageAllocator() override { return &page_allocator_; } - - std::shared_ptr GetForegroundTaskRunner() override { - return foreground_task_runner_; - } - - // TestPlatform does not support job priorities. All jobs would be assigned - // the same priority regardless of the cppgc::TaskPriority parameter. std::unique_ptr PostJob( - cppgc::TaskPriority, std::unique_ptr job_task) override; + cppgc::TaskPriority priority, + std::unique_ptr job_task) final; - double MonotonicallyIncreasingTime() override; - - void WaitAllForegroundTasks(); - void WaitAllBackgroundTasks(); + void RunAllForegroundTasks(); private: bool AreBackgroundTasksDisabled() const { return disabled_background_tasks_ > 0; } - v8::base::PageAllocator page_allocator_; - std::shared_ptr foreground_task_runner_; - std::vector> jobs_; size_t disabled_background_tasks_ = 0; };