1 // Copyright 2020 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/heap/cppgc/gc-invoker.h"
6 
7 #include "include/cppgc/platform.h"
8 #include "src/heap/cppgc/heap.h"
9 #include "test/unittests/heap/cppgc/test-platform.h"
10 #include "testing/gmock/include/gmock/gmock-matchers.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace cppgc {
15 namespace internal {
16 
17 namespace {
18 
19 class MockGarbageCollector : public GarbageCollector {
20  public:
21   MOCK_METHOD(void, CollectGarbage, (GarbageCollector::Config), (override));
22   MOCK_METHOD(void, StartIncrementalGarbageCollection,
23               (GarbageCollector::Config), (override));
24   MOCK_METHOD(size_t, epoch, (), (const, override));
25 };
26 
27 class MockTaskRunner : public cppgc::TaskRunner {
28  public:
29   MOCK_METHOD(void, PostTask, (std::unique_ptr<cppgc::Task>), (override));
30   MOCK_METHOD(void, PostNonNestableTask, (std::unique_ptr<cppgc::Task>),
31               (override));
32   MOCK_METHOD(void, PostDelayedTask, (std::unique_ptr<cppgc::Task>, double),
33               (override));
34   MOCK_METHOD(void, PostNonNestableDelayedTask,
35               (std::unique_ptr<cppgc::Task>, double), (override));
36   MOCK_METHOD(void, PostIdleTask, (std::unique_ptr<cppgc::IdleTask>),
37               (override));
38 
IdleTasksEnabled()39   bool IdleTasksEnabled() override { return true; }
NonNestableTasksEnabled() const40   bool NonNestableTasksEnabled() const override { return true; }
NonNestableDelayedTasksEnabled() const41   bool NonNestableDelayedTasksEnabled() const override { return true; }
42 };
43 
44 class MockPlatform : public cppgc::Platform {
45  public:
MockPlatform(std::shared_ptr<TaskRunner> runner)46   explicit MockPlatform(std::shared_ptr<TaskRunner> runner)
47       : runner_(std::move(runner)),
48         tracing_controller_(std::make_unique<TracingController>()) {}
49 
GetPageAllocator()50   PageAllocator* GetPageAllocator() override { return nullptr; }
MonotonicallyIncreasingTime()51   double MonotonicallyIncreasingTime() override { return 0.0; }
52 
GetForegroundTaskRunner()53   std::shared_ptr<TaskRunner> GetForegroundTaskRunner() override {
54     return runner_;
55   }
56 
GetTracingController()57   TracingController* GetTracingController() override {
58     return tracing_controller_.get();
59   }
60 
61  private:
62   std::shared_ptr<TaskRunner> runner_;
63   std::unique_ptr<TracingController> tracing_controller_;
64 };
65 
66 }  // namespace
67 
TEST(GCInvokerTest,PrecideGCIsInvokedSynchronously)68 TEST(GCInvokerTest, PrecideGCIsInvokedSynchronously) {
69   MockPlatform platform(nullptr);
70   MockGarbageCollector gc;
71   GCInvoker invoker(&gc, &platform,
72                     cppgc::Heap::StackSupport::kNoConservativeStackScan);
73   EXPECT_CALL(gc, CollectGarbage(::testing::Field(
74                       &GarbageCollector::Config::stack_state,
75                       GarbageCollector::Config::StackState::kNoHeapPointers)));
76   invoker.CollectGarbage(GarbageCollector::Config::PreciseAtomicConfig());
77 }
78 
TEST(GCInvokerTest,ConservativeGCIsInvokedSynchronouslyWhenSupported)79 TEST(GCInvokerTest, ConservativeGCIsInvokedSynchronouslyWhenSupported) {
80   MockPlatform platform(nullptr);
81   MockGarbageCollector gc;
82   GCInvoker invoker(&gc, &platform,
83                     cppgc::Heap::StackSupport::kSupportsConservativeStackScan);
84   EXPECT_CALL(
85       gc, CollectGarbage(::testing::Field(
86               &GarbageCollector::Config::stack_state,
87               GarbageCollector::Config::StackState::kMayContainHeapPointers)));
88   invoker.CollectGarbage(GarbageCollector::Config::ConservativeAtomicConfig());
89 }
90 
TEST(GCInvokerTest,ConservativeGCIsScheduledAsPreciseGCViaPlatform)91 TEST(GCInvokerTest, ConservativeGCIsScheduledAsPreciseGCViaPlatform) {
92   std::shared_ptr<cppgc::TaskRunner> runner =
93       std::shared_ptr<cppgc::TaskRunner>(new MockTaskRunner());
94   MockPlatform platform(runner);
95   MockGarbageCollector gc;
96   GCInvoker invoker(&gc, &platform,
97                     cppgc::Heap::StackSupport::kNoConservativeStackScan);
98   EXPECT_CALL(gc, epoch).WillOnce(::testing::Return(0));
99   EXPECT_CALL(*static_cast<MockTaskRunner*>(runner.get()),
100               PostNonNestableTask(::testing::_));
101   invoker.CollectGarbage(GarbageCollector::Config::ConservativeAtomicConfig());
102 }
103 
TEST(GCInvokerTest,ConservativeGCIsInvokedAsPreciseGCViaPlatform)104 TEST(GCInvokerTest, ConservativeGCIsInvokedAsPreciseGCViaPlatform) {
105   testing::TestPlatform platform;
106   MockGarbageCollector gc;
107   GCInvoker invoker(&gc, &platform,
108                     cppgc::Heap::StackSupport::kNoConservativeStackScan);
109   EXPECT_CALL(gc, epoch).WillRepeatedly(::testing::Return(0));
110   EXPECT_CALL(gc, CollectGarbage);
111   invoker.CollectGarbage(GarbageCollector::Config::ConservativeAtomicConfig());
112   platform.RunAllForegroundTasks();
113 }
114 
TEST(GCInvokerTest,IncrementalGCIsStarted)115 TEST(GCInvokerTest, IncrementalGCIsStarted) {
116   // Since StartIncrementalGarbageCollection doesn't scan the stack, support for
117   // conservative stack scanning should not matter.
118   MockPlatform platform(nullptr);
119   MockGarbageCollector gc;
120   // Conservative stack scanning supported.
121   GCInvoker invoker_with_support(
122       &gc, &platform,
123       cppgc::Heap::StackSupport::kSupportsConservativeStackScan);
124   EXPECT_CALL(
125       gc, StartIncrementalGarbageCollection(::testing::Field(
126               &GarbageCollector::Config::stack_state,
127               GarbageCollector::Config::StackState::kMayContainHeapPointers)));
128   invoker_with_support.StartIncrementalGarbageCollection(
129       GarbageCollector::Config::ConservativeIncrementalConfig());
130   // Conservative stack scanning *not* supported.
131   GCInvoker invoker_without_support(
132       &gc, &platform, cppgc::Heap::StackSupport::kNoConservativeStackScan);
133   EXPECT_CALL(
134       gc, StartIncrementalGarbageCollection(::testing::Field(
135               &GarbageCollector::Config::stack_state,
136               GarbageCollector::Config::StackState::kMayContainHeapPointers)))
137       .Times(0);
138   invoker_without_support.StartIncrementalGarbageCollection(
139       GarbageCollector::Config::ConservativeIncrementalConfig());
140 }
141 
142 }  // namespace internal
143 }  // namespace cppgc
144