1 // Copyright 2015 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 <stdlib.h>
6
7 #ifdef __linux__
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13 #endif
14
15 #include <utility>
16
17 #include "src/v8.h"
18
19 #include "src/full-codegen/full-codegen.h"
20 #include "src/global-handles.h"
21 #include "test/cctest/cctest.h"
22 #include "test/cctest/heap/utils-inl.h"
23
24
25 using v8::IdleTask;
26 using v8::Task;
27 using v8::Isolate;
28
29 namespace v8 {
30 namespace internal {
31
32 class MockPlatform : public v8::Platform {
33 public:
MockPlatform(v8::Platform * platform)34 explicit MockPlatform(v8::Platform* platform)
35 : platform_(platform), idle_task_(nullptr), delayed_task_(nullptr) {}
~MockPlatform()36 virtual ~MockPlatform() {
37 delete idle_task_;
38 delete delayed_task_;
39 }
40
CallOnBackgroundThread(Task * task,ExpectedRuntime expected_runtime)41 void CallOnBackgroundThread(Task* task,
42 ExpectedRuntime expected_runtime) override {
43 platform_->CallOnBackgroundThread(task, expected_runtime);
44 }
45
CallOnForegroundThread(v8::Isolate * isolate,Task * task)46 void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
47 platform_->CallOnForegroundThread(isolate, task);
48 }
49
CallDelayedOnForegroundThread(v8::Isolate * isolate,Task * task,double delay_in_seconds)50 void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
51 double delay_in_seconds) override {
52 if (delayed_task_ != nullptr) {
53 delete delayed_task_;
54 }
55 delayed_task_ = task;
56 }
57
MonotonicallyIncreasingTime()58 double MonotonicallyIncreasingTime() override {
59 return platform_->MonotonicallyIncreasingTime();
60 }
61
CallIdleOnForegroundThread(v8::Isolate * isolate,IdleTask * task)62 void CallIdleOnForegroundThread(v8::Isolate* isolate,
63 IdleTask* task) override {
64 CHECK(nullptr == idle_task_);
65 idle_task_ = task;
66 }
67
IdleTasksEnabled(v8::Isolate * isolate)68 bool IdleTasksEnabled(v8::Isolate* isolate) override { return true; }
69
PendingIdleTask()70 bool PendingIdleTask() { return idle_task_ != nullptr; }
71
PerformIdleTask(double idle_time_in_seconds)72 void PerformIdleTask(double idle_time_in_seconds) {
73 IdleTask* task = idle_task_;
74 idle_task_ = nullptr;
75 task->Run(MonotonicallyIncreasingTime() + idle_time_in_seconds);
76 delete task;
77 }
78
PendingDelayedTask()79 bool PendingDelayedTask() { return delayed_task_ != nullptr; }
80
PerformDelayedTask()81 void PerformDelayedTask() {
82 Task* task = delayed_task_;
83 delayed_task_ = nullptr;
84 task->Run();
85 delete task;
86 }
87
AddTraceEvent(char phase,const uint8_t * categoryEnabledFlag,const char * name,uint64_t id,uint64_t bind_id,int numArgs,const char ** argNames,const uint8_t * argTypes,const uint64_t * argValues,unsigned int flags)88 uint64_t AddTraceEvent(char phase, const uint8_t* categoryEnabledFlag,
89 const char* name, uint64_t id, uint64_t bind_id,
90 int numArgs, const char** argNames,
91 const uint8_t* argTypes, const uint64_t* argValues,
92 unsigned int flags) override {
93 return 0;
94 }
95
UpdateTraceEventDuration(const uint8_t * categoryEnabledFlag,const char * name,uint64_t handle)96 void UpdateTraceEventDuration(const uint8_t* categoryEnabledFlag,
97 const char* name, uint64_t handle) override {}
98
GetCategoryGroupEnabled(const char * name)99 const uint8_t* GetCategoryGroupEnabled(const char* name) override {
100 static uint8_t no = 0;
101 return &no;
102 }
103
GetCategoryGroupName(const uint8_t * categoryEnabledFlag)104 const char* GetCategoryGroupName(
105 const uint8_t* categoryEnabledFlag) override {
106 static const char* dummy = "dummy";
107 return dummy;
108 }
109
110 private:
111 v8::Platform* platform_;
112 IdleTask* idle_task_;
113 Task* delayed_task_;
114 };
115
116
TEST(IncrementalMarkingUsingIdleTasks)117 TEST(IncrementalMarkingUsingIdleTasks) {
118 if (!i::FLAG_incremental_marking) return;
119 CcTest::InitializeVM();
120 v8::Platform* old_platform = i::V8::GetCurrentPlatform();
121 MockPlatform platform(old_platform);
122 i::V8::SetPlatformForTesting(&platform);
123 SimulateFullSpace(CcTest::heap()->old_space());
124 i::IncrementalMarking* marking = CcTest::heap()->incremental_marking();
125 marking->Stop();
126 marking->Start();
127 CHECK(platform.PendingIdleTask());
128 const double kLongIdleTimeInSeconds = 1;
129 const double kShortIdleTimeInSeconds = 0.010;
130 const int kShortStepCount = 10;
131 for (int i = 0; i < kShortStepCount && platform.PendingIdleTask(); i++) {
132 platform.PerformIdleTask(kShortIdleTimeInSeconds);
133 }
134 while (platform.PendingIdleTask()) {
135 platform.PerformIdleTask(kLongIdleTimeInSeconds);
136 }
137 CHECK(marking->IsStopped());
138 i::V8::SetPlatformForTesting(old_platform);
139 }
140
141
TEST(IncrementalMarkingUsingIdleTasksAfterGC)142 TEST(IncrementalMarkingUsingIdleTasksAfterGC) {
143 if (!i::FLAG_incremental_marking) return;
144 CcTest::InitializeVM();
145 v8::Platform* old_platform = i::V8::GetCurrentPlatform();
146 MockPlatform platform(old_platform);
147 i::V8::SetPlatformForTesting(&platform);
148 SimulateFullSpace(CcTest::heap()->old_space());
149 CcTest::heap()->CollectAllGarbage();
150 i::IncrementalMarking* marking = CcTest::heap()->incremental_marking();
151 marking->Stop();
152 marking->Start();
153 CHECK(platform.PendingIdleTask());
154 const double kLongIdleTimeInSeconds = 1;
155 const double kShortIdleTimeInSeconds = 0.010;
156 const int kShortStepCount = 10;
157 for (int i = 0; i < kShortStepCount && platform.PendingIdleTask(); i++) {
158 platform.PerformIdleTask(kShortIdleTimeInSeconds);
159 }
160 while (platform.PendingIdleTask()) {
161 platform.PerformIdleTask(kLongIdleTimeInSeconds);
162 }
163 CHECK(marking->IsStopped());
164 i::V8::SetPlatformForTesting(old_platform);
165 }
166
167
TEST(IncrementalMarkingUsingDelayedTasks)168 TEST(IncrementalMarkingUsingDelayedTasks) {
169 if (!i::FLAG_incremental_marking) return;
170 CcTest::InitializeVM();
171 v8::Platform* old_platform = i::V8::GetCurrentPlatform();
172 MockPlatform platform(old_platform);
173 i::V8::SetPlatformForTesting(&platform);
174 SimulateFullSpace(CcTest::heap()->old_space());
175 i::IncrementalMarking* marking = CcTest::heap()->incremental_marking();
176 marking->Stop();
177 marking->Start();
178 CHECK(platform.PendingIdleTask());
179 // The delayed task should be a no-op if the idle task makes progress.
180 const int kIgnoredDelayedTaskStepCount = 1000;
181 for (int i = 0; i < kIgnoredDelayedTaskStepCount; i++) {
182 // Dummy idle task progress.
183 marking->incremental_marking_job()->NotifyIdleTaskProgress();
184 CHECK(platform.PendingDelayedTask());
185 platform.PerformDelayedTask();
186 }
187 // Once we stop notifying idle task progress, the delayed tasks
188 // should finish marking.
189 while (!marking->IsStopped() && platform.PendingDelayedTask()) {
190 platform.PerformDelayedTask();
191 }
192 // There could be pending delayed task from memory reducer after GC finishes.
193 CHECK(marking->IsStopped());
194 i::V8::SetPlatformForTesting(old_platform);
195 }
196
197 } // namespace internal
198 } // namespace v8
199