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