OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "modules/compositorworker/CompositorWorkerThread.h" | 5 #include "modules/compositorworker/AnimationWorkletThread.h" |
6 | 6 |
7 #include "bindings/core/v8/ScriptSourceCode.h" | 7 #include "bindings/core/v8/ScriptSourceCode.h" |
8 #include "bindings/core/v8/SourceLocation.h" | 8 #include "bindings/core/v8/SourceLocation.h" |
9 #include "bindings/core/v8/V8GCController.h" | 9 #include "bindings/core/v8/V8GCController.h" |
10 #include "bindings/core/v8/WorkerOrWorkletScriptController.h" | 10 #include "bindings/core/v8/WorkerOrWorkletScriptController.h" |
11 #include "core/dom/CompositorProxyClient.h" | |
12 #include "core/inspector/ConsoleMessage.h" | 11 #include "core/inspector/ConsoleMessage.h" |
13 #include "core/testing/DummyPageHolder.h" | |
14 #include "core/workers/InProcessWorkerObjectProxy.h" | 12 #include "core/workers/InProcessWorkerObjectProxy.h" |
15 #include "core/workers/WorkerBackingThread.h" | 13 #include "core/workers/WorkerBackingThread.h" |
16 #include "core/workers/WorkerLoaderProxy.h" | 14 #include "core/workers/WorkerLoaderProxy.h" |
17 #include "core/workers/WorkerOrWorkletGlobalScope.h" | 15 #include "core/workers/WorkerOrWorkletGlobalScope.h" |
18 #include "core/workers/WorkerThreadStartupData.h" | 16 #include "core/workers/WorkerThreadStartupData.h" |
19 #include "platform/CrossThreadFunctional.h" | 17 #include "platform/CrossThreadFunctional.h" |
20 #include "platform/WaitableEvent.h" | 18 #include "platform/WaitableEvent.h" |
21 #include "platform/WebThreadSupportingGC.h" | 19 #include "platform/WebThreadSupportingGC.h" |
22 #include "platform/heap/Handle.h" | 20 #include "platform/heap/Handle.h" |
23 #include "platform/testing/TestingPlatformSupport.h" | 21 #include "platform/testing/TestingPlatformSupport.h" |
24 #include "platform/testing/UnitTestHelpers.h" | 22 #include "platform/testing/UnitTestHelpers.h" |
25 #include "public/platform/Platform.h" | 23 #include "public/platform/Platform.h" |
26 #include "public/platform/WebAddressSpace.h" | 24 #include "public/platform/WebAddressSpace.h" |
27 #include "testing/gtest/include/gtest/gtest.h" | 25 #include "testing/gtest/include/gtest/gtest.h" |
28 #include "wtf/PtrUtil.h" | 26 #include "wtf/PtrUtil.h" |
29 #include <memory> | 27 #include <memory> |
30 | 28 |
31 namespace blink { | 29 namespace blink { |
32 namespace { | 30 namespace { |
33 | 31 |
34 // A null InProcessWorkerObjectProxy, supplied when creating CompositorWorkerThr
eads. | 32 // A null WorkerReportingProxy, supplied when creating AnimationWorkletThreads. |
35 class TestCompositorWorkerObjectProxy : public InProcessWorkerObjectProxy { | 33 class TestAnimationWorkletReportingProxy : public WorkerReportingProxy { |
36 public: | 34 public: |
37 static std::unique_ptr<TestCompositorWorkerObjectProxy> create(ExecutionCont
ext* context) | 35 static std::unique_ptr<TestAnimationWorkletReportingProxy> create() |
38 { | 36 { |
39 return wrapUnique(new TestCompositorWorkerObjectProxy(context)); | 37 return wrapUnique(new TestAnimationWorkletReportingProxy()); |
40 } | 38 } |
41 | 39 |
42 // (Empty) WorkerReportingProxy implementation: | 40 // (Empty) WorkerReportingProxy implementation: |
43 virtual void dispatchErrorEvent(const String& errorMessage, std::unique_ptr<
SourceLocation>, int exceptionId) {} | 41 void reportException(const String& errorMessage, std::unique_ptr<SourceLocat
ion>, int exceptionId) override {} |
44 void reportConsoleMessage(MessageSource, MessageLevel, const String& message
, SourceLocation*) override {} | 42 void reportConsoleMessage(MessageSource, MessageLevel, const String& message
, SourceLocation*) override {} |
45 void postMessageToPageInspector(const String&) override {} | 43 void postMessageToPageInspector(const String&) override {} |
46 | 44 |
47 void didEvaluateWorkerScript(bool success) override {} | 45 void didEvaluateWorkerScript(bool success) override {} |
48 void workerGlobalScopeStarted(WorkerOrWorkletGlobalScope*) override {} | 46 void workerGlobalScopeStarted(WorkerOrWorkletGlobalScope*) override {} |
49 void workerGlobalScopeClosed() override {} | 47 void workerGlobalScopeClosed() override {} |
50 void workerThreadTerminated() override {} | 48 void workerThreadTerminated() override {} |
51 void willDestroyWorkerGlobalScope() override {} | 49 void willDestroyWorkerGlobalScope() override {} |
52 | 50 |
53 ExecutionContext* getExecutionContext() override { return m_executionContext
.get(); } | |
54 | |
55 private: | 51 private: |
56 TestCompositorWorkerObjectProxy(ExecutionContext* context) | 52 TestAnimationWorkletReportingProxy() {} |
57 : InProcessWorkerObjectProxy(nullptr) | |
58 , m_executionContext(context) | |
59 { | |
60 } | |
61 | |
62 Persistent<ExecutionContext> m_executionContext; | |
63 }; | 53 }; |
64 | 54 |
65 class TestCompositorProxyClient | 55 class AnimationWorkletTestPlatform : public TestingPlatformSupport { |
66 : public GarbageCollected<TestCompositorProxyClient> | |
67 , public CompositorProxyClient { | |
68 USING_GARBAGE_COLLECTED_MIXIN(TestCompositorProxyClient); | |
69 public: | 56 public: |
70 TestCompositorProxyClient() {} | 57 AnimationWorkletTestPlatform() |
71 | |
72 void setGlobalScope(WorkerGlobalScope*) override {} | |
73 void requestAnimationFrame() override {} | |
74 void registerCompositorProxy(CompositorProxy*) override {} | |
75 void unregisterCompositorProxy(CompositorProxy*) override {} | |
76 }; | |
77 | |
78 class CompositorWorkerTestPlatform : public TestingPlatformSupport { | |
79 public: | |
80 CompositorWorkerTestPlatform() | |
81 : m_thread(wrapUnique(m_oldPlatform->createThread("Compositor"))) | 58 : m_thread(wrapUnique(m_oldPlatform->createThread("Compositor"))) |
82 { | 59 { |
83 } | 60 } |
84 | 61 |
85 WebThread* compositorThread() const override | 62 WebThread* compositorThread() const override |
86 { | 63 { |
87 return m_thread.get(); | 64 return m_thread.get(); |
88 } | 65 } |
89 | 66 |
90 WebCompositorSupport* compositorSupport() override { return &m_compositorSup
port; } | 67 WebCompositorSupport* compositorSupport() override { return &m_compositorSup
port; } |
91 | 68 |
92 private: | 69 private: |
93 std::unique_ptr<WebThread> m_thread; | 70 std::unique_ptr<WebThread> m_thread; |
94 TestingCompositorSupport m_compositorSupport; | 71 TestingCompositorSupport m_compositorSupport; |
95 }; | 72 }; |
96 | 73 |
97 } // namespace | 74 } // namespace |
98 | 75 |
99 class CompositorWorkerThreadTest : public ::testing::Test { | 76 class AnimationWorkletThreadTest : public ::testing::Test { |
100 public: | 77 public: |
101 void SetUp() override | 78 void SetUp() override |
102 { | 79 { |
103 CompositorWorkerThread::createSharedBackingThreadForTest(); | 80 AnimationWorkletThread::createSharedBackingThreadForTest(); |
104 m_page = DummyPageHolder::create(); | 81 m_reportingProxy = TestAnimationWorkletReportingProxy::create(); |
105 m_objectProxy = TestCompositorWorkerObjectProxy::create(&m_page->documen
t()); | |
106 m_securityOrigin = SecurityOrigin::create(KURL(ParsedURLString, "http://
fake.url/")); | 82 m_securityOrigin = SecurityOrigin::create(KURL(ParsedURLString, "http://
fake.url/")); |
107 } | 83 } |
108 | 84 |
109 void TearDown() override | 85 void TearDown() override |
110 { | 86 { |
111 m_page.reset(); | 87 AnimationWorkletThread::clearSharedBackingThread(); |
112 CompositorWorkerThread::clearSharedBackingThread(); | |
113 } | 88 } |
114 | 89 |
115 std::unique_ptr<CompositorWorkerThread> createCompositorWorker() | 90 std::unique_ptr<AnimationWorkletThread> createAnimationWorkletThread() |
116 { | 91 { |
117 std::unique_ptr<CompositorWorkerThread> workerThread = CompositorWorkerT
hread::create(nullptr, *m_objectProxy, 0); | 92 std::unique_ptr<AnimationWorkletThread> thread = AnimationWorkletThread:
:create(nullptr, *m_reportingProxy); |
118 WorkerClients* clients = WorkerClients::create(); | 93 thread->start(WorkerThreadStartupData::create( |
119 provideCompositorProxyClientTo(clients, new TestCompositorProxyClient); | |
120 workerThread->start(WorkerThreadStartupData::create( | |
121 KURL(ParsedURLString, "http://fake.url/"), | 94 KURL(ParsedURLString, "http://fake.url/"), |
122 "fake user agent", | 95 "fake user agent", |
123 "//fake source code", | 96 "", |
124 nullptr, | 97 nullptr, |
125 DontPauseWorkerGlobalScopeOnStart, | 98 DontPauseWorkerGlobalScopeOnStart, |
126 nullptr, | 99 nullptr, |
127 "", | 100 "", |
128 m_securityOrigin.get(), | 101 m_securityOrigin.get(), |
129 clients, | 102 nullptr, |
130 WebAddressSpaceLocal, | 103 WebAddressSpaceLocal, |
131 nullptr, | 104 nullptr, |
132 nullptr, | 105 nullptr, |
133 V8CacheOptionsDefault)); | 106 V8CacheOptionsDefault)); |
134 return workerThread; | 107 return thread; |
135 } | 108 } |
136 | 109 |
137 // Attempts to run some simple script for |worker|. | 110 // Attempts to run some simple script for |thread|. |
138 void checkWorkerCanExecuteScript(WorkerThread* worker) | 111 void checkWorkletCanExecuteScript(WorkerThread* thread) |
139 { | 112 { |
140 std::unique_ptr<WaitableEvent> waitEvent = wrapUnique(new WaitableEvent(
)); | 113 std::unique_ptr<WaitableEvent> waitEvent = wrapUnique(new WaitableEvent(
)); |
141 worker->workerBackingThread().backingThread().postTask(BLINK_FROM_HERE,
crossThreadBind(&CompositorWorkerThreadTest::executeScriptInWorker, crossThreadU
nretained(this), | 114 thread->workerBackingThread().backingThread().postTask(BLINK_FROM_HERE,
crossThreadBind(&AnimationWorkletThreadTest::executeScriptInWorklet, crossThread
Unretained(this), |
142 crossThreadUnretained(worker), crossThreadUnretained(waitEvent.get()
))); | 115 crossThreadUnretained(thread), crossThreadUnretained(waitEvent.get()
))); |
143 waitEvent->wait(); | 116 waitEvent->wait(); |
144 } | 117 } |
145 | 118 |
146 private: | 119 private: |
147 void executeScriptInWorker(WorkerThread* worker, WaitableEvent* waitEvent) | 120 void executeScriptInWorklet(WorkerThread* thread, WaitableEvent* waitEvent) |
148 { | 121 { |
149 WorkerOrWorkletScriptController* scriptController = worker->globalScope(
)->scriptController(); | 122 WorkerOrWorkletScriptController* scriptController = thread->globalScope(
)->scriptController(); |
150 bool evaluateResult = scriptController->evaluate(ScriptSourceCode("var c
ounter = 0; ++counter;")); | 123 scriptController->evaluate(ScriptSourceCode("var counter = 0; ++counter;
")); |
151 ASSERT_UNUSED(evaluateResult, evaluateResult); | |
152 waitEvent->signal(); | 124 waitEvent->signal(); |
153 } | 125 } |
154 | 126 |
155 std::unique_ptr<DummyPageHolder> m_page; | |
156 RefPtr<SecurityOrigin> m_securityOrigin; | 127 RefPtr<SecurityOrigin> m_securityOrigin; |
157 std::unique_ptr<InProcessWorkerObjectProxy> m_objectProxy; | 128 std::unique_ptr<WorkerReportingProxy> m_reportingProxy; |
158 CompositorWorkerTestPlatform m_testPlatform; | 129 AnimationWorkletTestPlatform m_testPlatform; |
159 }; | 130 }; |
160 | 131 |
161 TEST_F(CompositorWorkerThreadTest, Basic) | 132 TEST_F(AnimationWorkletThreadTest, Basic) |
162 { | 133 { |
163 std::unique_ptr<CompositorWorkerThread> compositorWorker = createCompositorW
orker(); | 134 std::unique_ptr<AnimationWorkletThread> worklet = createAnimationWorkletThre
ad(); |
164 checkWorkerCanExecuteScript(compositorWorker.get()); | 135 checkWorkletCanExecuteScript(worklet.get()); |
165 compositorWorker->terminateAndWait(); | 136 worklet->terminateAndWait(); |
166 } | 137 } |
167 | 138 |
168 // Tests that the same WebThread is used for new workers if the WebThread is sti
ll alive. | 139 // Tests that the same WebThread is used for new worklets if the WebThread is |
169 TEST_F(CompositorWorkerThreadTest, CreateSecondAndTerminateFirst) | 140 // still alive. |
| 141 TEST_F(AnimationWorkletThreadTest, CreateSecondAndTerminateFirst) |
170 { | 142 { |
171 // Create the first worker and wait until it is initialized. | 143 // Create the first worklet and wait until it is initialized. |
172 std::unique_ptr<CompositorWorkerThread> firstWorker = createCompositorWorker
(); | 144 std::unique_ptr<AnimationWorkletThread> firstWorklet = createAnimationWorkle
tThread(); |
173 WebThreadSupportingGC* firstThread = &firstWorker->workerBackingThread().bac
kingThread(); | 145 WebThreadSupportingGC* firstThread = &firstWorklet->workerBackingThread().ba
ckingThread(); |
174 checkWorkerCanExecuteScript(firstWorker.get()); | 146 checkWorkletCanExecuteScript(firstWorklet.get()); |
175 v8::Isolate* firstIsolate = firstWorker->isolate(); | 147 v8::Isolate* firstIsolate = firstWorklet->isolate(); |
176 ASSERT_TRUE(firstIsolate); | 148 ASSERT_TRUE(firstIsolate); |
177 | 149 |
178 // Create the second worker and immediately destroy the first worker. | 150 // Create the second worklet and immediately destroy the first worklet. |
179 std::unique_ptr<CompositorWorkerThread> secondWorker = createCompositorWorke
r(); | 151 std::unique_ptr<AnimationWorkletThread> secondWorklet = createAnimationWorkl
etThread(); |
180 // We don't use terminateAndWait here to avoid forcible termination. | 152 // We don't use terminateAndWait here to avoid forcible termination. |
181 firstWorker->terminate(); | 153 firstWorklet->terminate(); |
182 firstWorker->waitForShutdownForTesting(); | 154 firstWorklet->waitForShutdownForTesting(); |
183 | 155 |
184 // Wait until the second worker is initialized. Verify that the second worke
r is using the same | 156 // Wait until the second worklet is initialized. Verify that the second |
185 // thread and Isolate as the first worker. | 157 // worklet is using the same thread and Isolate as the first worklet. |
186 WebThreadSupportingGC* secondThread = &secondWorker->workerBackingThread().b
ackingThread(); | 158 WebThreadSupportingGC* secondThread = &secondWorklet->workerBackingThread().
backingThread(); |
187 ASSERT_EQ(firstThread, secondThread); | 159 ASSERT_EQ(firstThread, secondThread); |
188 | 160 |
189 v8::Isolate* secondIsolate = secondWorker->isolate(); | 161 v8::Isolate* secondIsolate = secondWorklet->isolate(); |
190 ASSERT_TRUE(secondIsolate); | 162 ASSERT_TRUE(secondIsolate); |
191 EXPECT_EQ(firstIsolate, secondIsolate); | 163 EXPECT_EQ(firstIsolate, secondIsolate); |
192 | 164 |
193 // Verify that the worker can still successfully execute script. | 165 // Verify that the worklet can still successfully execute script. |
194 checkWorkerCanExecuteScript(secondWorker.get()); | 166 checkWorkletCanExecuteScript(secondWorklet.get()); |
195 | 167 |
196 secondWorker->terminateAndWait(); | 168 secondWorklet->terminateAndWait(); |
197 } | 169 } |
198 | 170 |
199 // Tests that a new WebThread is created if all existing workers are terminated
before a new worker is created. | 171 // Tests that a new WebThread is created if all existing worklets are |
200 TEST_F(CompositorWorkerThreadTest, TerminateFirstAndCreateSecond) | 172 // terminated before a new worklet is created. |
| 173 TEST_F(AnimationWorkletThreadTest, TerminateFirstAndCreateSecond) |
201 { | 174 { |
202 // Create the first worker, wait until it is initialized, and terminate it. | 175 // Create the first worklet, wait until it is initialized, and terminate it. |
203 std::unique_ptr<CompositorWorkerThread> compositorWorker = createCompositorW
orker(); | 176 std::unique_ptr<AnimationWorkletThread> worklet = createAnimationWorkletThre
ad(); |
204 WebThreadSupportingGC* firstThread = &compositorWorker->workerBackingThread(
).backingThread(); | 177 WebThreadSupportingGC* firstThread = &worklet->workerBackingThread().backing
Thread(); |
205 checkWorkerCanExecuteScript(compositorWorker.get()); | 178 checkWorkletCanExecuteScript(worklet.get()); |
206 | 179 |
207 // We don't use terminateAndWait here to avoid forcible termination. | 180 // We don't use terminateAndWait here to avoid forcible termination. |
208 compositorWorker->terminate(); | 181 worklet->terminate(); |
209 compositorWorker->waitForShutdownForTesting(); | 182 worklet->waitForShutdownForTesting(); |
210 | 183 |
211 // Create the second worker. The backing thread is same. | 184 // Create the second worklet. The backing thread is same. |
212 compositorWorker = createCompositorWorker(); | 185 worklet = createAnimationWorkletThread(); |
213 WebThreadSupportingGC* secondThread = &compositorWorker->workerBackingThread
().backingThread(); | 186 WebThreadSupportingGC* secondThread = &worklet->workerBackingThread().backin
gThread(); |
214 EXPECT_EQ(firstThread, secondThread); | 187 EXPECT_EQ(firstThread, secondThread); |
215 checkWorkerCanExecuteScript(compositorWorker.get()); | 188 checkWorkletCanExecuteScript(worklet.get()); |
216 | 189 |
217 compositorWorker->terminateAndWait(); | 190 worklet->terminateAndWait(); |
218 } | 191 } |
219 | 192 |
220 // Tests that v8::Isolate and WebThread are correctly set-up if a worker is crea
ted while another is terminating. | 193 // Tests that v8::Isolate and WebThread are correctly set-up if a worklet is |
221 TEST_F(CompositorWorkerThreadTest, CreatingSecondDuringTerminationOfFirst) | 194 // created while another is terminating. |
| 195 TEST_F(AnimationWorkletThreadTest, CreatingSecondDuringTerminationOfFirst) |
222 { | 196 { |
223 std::unique_ptr<CompositorWorkerThread> firstWorker = createCompositorWorker
(); | 197 std::unique_ptr<AnimationWorkletThread> firstWorklet = createAnimationWorkle
tThread(); |
224 checkWorkerCanExecuteScript(firstWorker.get()); | 198 checkWorkletCanExecuteScript(firstWorklet.get()); |
225 v8::Isolate* firstIsolate = firstWorker->isolate(); | 199 v8::Isolate* firstIsolate = firstWorklet->isolate(); |
226 ASSERT_TRUE(firstIsolate); | 200 ASSERT_TRUE(firstIsolate); |
227 | 201 |
228 // Request termination of the first worker and create the second worker | 202 // Request termination of the first worklet and create the second worklet |
229 // as soon as possible. | 203 // as soon as possible. |
230 firstWorker->terminate(); | 204 firstWorklet->terminate(); |
231 // We don't wait for its termination. | 205 // We don't wait for its termination. |
232 // Note: We rely on the assumption that the termination steps don't run | 206 // Note: We rely on the assumption that the termination steps don't run |
233 // on the worker thread so quickly. This could be a source of flakiness. | 207 // on the worklet thread so quickly. This could be a source of flakiness. |
234 | 208 |
235 std::unique_ptr<CompositorWorkerThread> secondWorker = createCompositorWorke
r(); | 209 std::unique_ptr<AnimationWorkletThread> secondWorklet = createAnimationWorkl
etThread(); |
236 | 210 |
237 v8::Isolate* secondIsolate = secondWorker->isolate(); | 211 v8::Isolate* secondIsolate = secondWorklet->isolate(); |
238 ASSERT_TRUE(secondIsolate); | 212 ASSERT_TRUE(secondIsolate); |
239 EXPECT_EQ(firstIsolate, secondIsolate); | 213 EXPECT_EQ(firstIsolate, secondIsolate); |
240 | 214 |
241 // Verify that the isolate can run some scripts correctly in the second work
er. | 215 // Verify that the isolate can run some scripts correctly in the second |
242 checkWorkerCanExecuteScript(secondWorker.get()); | 216 // worklet. |
243 secondWorker->terminateAndWait(); | 217 checkWorkletCanExecuteScript(secondWorklet.get()); |
| 218 secondWorklet->terminateAndWait(); |
244 } | 219 } |
245 | 220 |
246 } // namespace blink | 221 } // namespace blink |
OLD | NEW |