Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: Source/bindings/core/v8/ScriptStreamerTest.cpp

Issue 651163002: Script streaming: Add an option to make the main thread block (wait for parsing) (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: code review (jochen@, skyostil@) Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 5
6 #include "config.h" 6 #include "config.h"
7 #include "bindings/core/v8/ScriptStreamer.h" 7 #include "bindings/core/v8/ScriptStreamer.h"
8 8
9 #include "bindings/core/v8/ScriptSourceCode.h" 9 #include "bindings/core/v8/ScriptSourceCode.h"
10 #include "bindings/core/v8/ScriptStreamerThread.h" 10 #include "bindings/core/v8/ScriptStreamerThread.h"
11 #include "bindings/core/v8/ScriptStreamingMode.h"
11 #include "bindings/core/v8/V8Binding.h" 12 #include "bindings/core/v8/V8Binding.h"
12 #include "bindings/core/v8/V8ScriptRunner.h" 13 #include "bindings/core/v8/V8ScriptRunner.h"
13 #include "core/dom/PendingScript.h" 14 #include "core/dom/PendingScript.h"
14 #include "core/frame/Settings.h" 15 #include "core/frame/Settings.h"
15 #include "platform/Task.h" 16 #include "platform/Task.h"
16 #include "platform/heap/Handle.h" 17 #include "platform/heap/Handle.h"
17 #include "public/platform/Platform.h" 18 #include "public/platform/Platform.h"
18 19
19 #include <gtest/gtest.h> 20 #include <gtest/gtest.h>
20 #include <v8.h> 21 #include <v8.h>
(...skipping 30 matching lines...) Expand all
51 } 52 }
52 53
53 PendingScriptWrapper(Element* element, ScriptResource* resource) 54 PendingScriptWrapper(Element* element, ScriptResource* resource)
54 : m_pendingScript(PendingScript(element, resource)) 55 : m_pendingScript(PendingScript(element, resource))
55 { 56 {
56 } 57 }
57 58
58 PendingScript m_pendingScript; 59 PendingScript m_pendingScript;
59 }; 60 };
60 61
61 class ScriptStreamingTest : public testing::Test { 62 // The bool param for ScriptStreamingTest controls whether to make the main
63 // thread block and wait for parsing.
64 class ScriptStreamingTest : public testing::TestWithParam<bool> {
62 public: 65 public:
63 ScriptStreamingTest() 66 ScriptStreamingTest()
64 : m_scope(v8::Isolate::GetCurrent()) 67 : m_scope(v8::Isolate::GetCurrent())
65 , m_settings(Settings::create()) 68 , m_settings(Settings::create())
66 , m_resourceRequest("http://www.streaming-test.com/") 69 , m_resourceRequest("http://www.streaming-test.com/")
67 , m_resource(new ScriptResource(m_resourceRequest, "text/utf-8")) 70 , m_resource(new ScriptResource(m_resourceRequest, "text/utf-8"))
68 , m_pendingScript(PendingScriptWrapper::create(0, m_resource)) // Takes ownership of m_resource. 71 , m_pendingScript(PendingScriptWrapper::create(0, m_resource)) // Takes ownership of m_resource.
69 { 72 {
70 m_settings->setV8ScriptStreamingEnabled(true); 73 m_settings->setV8ScriptStreamingEnabled(true);
74 if (GetParam())
75 m_settings->setV8ScriptStreamingMode(ScriptStreamingModeAllPlusBlock ParsingBlocking);
71 m_resource->setLoading(true); 76 m_resource->setLoading(true);
72 ScriptStreamer::setSmallScriptThresholdForTesting(0); 77 ScriptStreamer::setSmallScriptThresholdForTesting(0);
73 } 78 }
74 79
75 ScriptState* scriptState() const { return m_scope.scriptState(); } 80 ScriptState* scriptState() const { return m_scope.scriptState(); }
76 v8::Isolate* isolate() const { return m_scope.isolate(); } 81 v8::Isolate* isolate() const { return m_scope.isolate(); }
77 82
78 PendingScript& pendingScript() const { return m_pendingScript->get(); } 83 PendingScript& pendingScript() const { return m_pendingScript->get(); }
79 84
80 protected: 85 protected:
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 : m_finished(false) { } 138 : m_finished(false) { }
134 139
135 virtual void notifyFinished(Resource*) override { m_finished = true; } 140 virtual void notifyFinished(Resource*) override { m_finished = true; }
136 141
137 bool finished() const { return m_finished; } 142 bool finished() const { return m_finished; }
138 143
139 private: 144 private:
140 bool m_finished; 145 bool m_finished;
141 }; 146 };
142 147
143 TEST_F(ScriptStreamingTest, CompilingStreamedScript) 148 TEST_P(ScriptStreamingTest, CompilingStreamedScript)
144 { 149 {
145 // Test that we can successfully compile a streamed script. 150 // Test that we can successfully compile a streamed script.
146 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking); 151 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking);
147 TestScriptResourceClient client; 152 TestScriptResourceClient client;
148 pendingScript().watchForLoad(&client); 153 pendingScript().watchForLoad(&client);
149 154
150 appendData("function foo() {"); 155 appendData("function foo() {");
151 appendPadding(); 156 appendPadding();
152 appendData("return 5; }"); 157 appendData("return 5; }");
153 appendPadding(); 158 appendPadding();
154 appendData("foo();"); 159 appendData("foo();");
155 EXPECT_FALSE(client.finished()); 160 EXPECT_FALSE(client.finished());
156 finish(); 161 finish();
157 162
158 // Process tasks on the main thread until the streaming background thread 163 // Process tasks on the main thread until the streaming background thread
159 // has completed its tasks. 164 // has completed its tasks.
160 processTasksUntilStreamingComplete(); 165 processTasksUntilStreamingComplete();
161 EXPECT_TRUE(client.finished()); 166 EXPECT_TRUE(client.finished());
162 bool errorOccurred = false; 167 bool errorOccurred = false;
163 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre d); 168 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre d);
164 EXPECT_FALSE(errorOccurred); 169 EXPECT_FALSE(errorOccurred);
165 EXPECT_TRUE(sourceCode.streamer()); 170 EXPECT_TRUE(sourceCode.streamer());
166 v8::TryCatch tryCatch; 171 v8::TryCatch tryCatch;
167 v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, is olate()); 172 v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, is olate());
168 EXPECT_FALSE(script.IsEmpty()); 173 EXPECT_FALSE(script.IsEmpty());
169 EXPECT_FALSE(tryCatch.HasCaught()); 174 EXPECT_FALSE(tryCatch.HasCaught());
170 } 175 }
171 176
172 TEST_F(ScriptStreamingTest, CompilingStreamedScriptWithParseError) 177 TEST_P(ScriptStreamingTest, CompilingStreamedScriptWithParseError)
173 { 178 {
174 // Test that scripts with parse errors are handled properly. In those cases, 179 // Test that scripts with parse errors are handled properly. In those cases,
175 // the V8 side typically finished before loading finishes: make sure we 180 // the V8 side typically finished before loading finishes: make sure we
176 // handle it gracefully. 181 // handle it gracefully.
177 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking); 182 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking);
178 TestScriptResourceClient client; 183 TestScriptResourceClient client;
179 pendingScript().watchForLoad(&client); 184 pendingScript().watchForLoad(&client);
180 appendData("function foo() {"); 185 appendData("function foo() {");
181 appendData("this is the part which will be a parse error"); 186 appendData("this is the part which will be a parse error");
182 // V8 won't realize the parse error until it actually starts parsing the 187 // V8 won't realize the parse error until it actually starts parsing the
(...skipping 12 matching lines...) Expand all
195 bool errorOccurred = false; 200 bool errorOccurred = false;
196 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre d); 201 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre d);
197 EXPECT_FALSE(errorOccurred); 202 EXPECT_FALSE(errorOccurred);
198 EXPECT_TRUE(sourceCode.streamer()); 203 EXPECT_TRUE(sourceCode.streamer());
199 v8::TryCatch tryCatch; 204 v8::TryCatch tryCatch;
200 v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, is olate()); 205 v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, is olate());
201 EXPECT_TRUE(script.IsEmpty()); 206 EXPECT_TRUE(script.IsEmpty());
202 EXPECT_TRUE(tryCatch.HasCaught()); 207 EXPECT_TRUE(tryCatch.HasCaught());
203 } 208 }
204 209
205 TEST_F(ScriptStreamingTest, CancellingStreaming) 210 TEST_P(ScriptStreamingTest, CancellingStreaming)
206 { 211 {
207 // Test that the upper layers (PendingScript and up) can be ramped down 212 // Test that the upper layers (PendingScript and up) can be ramped down
208 // while streaming is ongoing, and ScriptStreamer handles it gracefully. 213 // while streaming is ongoing, and ScriptStreamer handles it gracefully.
209 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking); 214 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking);
210 TestScriptResourceClient client; 215 TestScriptResourceClient client;
211 pendingScript().watchForLoad(&client); 216 pendingScript().watchForLoad(&client);
212 appendData("function foo() {"); 217 appendData("function foo() {");
213 218
214 // In general, we cannot control what the background thread is doing 219 // In general, we cannot control what the background thread is doing
215 // (whether it's parsing or waiting for more data). In this test, we have 220 // (whether it's parsing or waiting for more data). In this test, we have
216 // given it so little data that it's surely waiting for more. 221 // given it so little data that it's surely waiting for more.
217 222
218 // Simulate cancelling the network load (e.g., because the user navigated 223 // Simulate cancelling the network load (e.g., because the user navigated
219 // away). 224 // away).
220 EXPECT_FALSE(client.finished()); 225 EXPECT_FALSE(client.finished());
221 pendingScript().stopWatchingForLoad(&client); 226 pendingScript().stopWatchingForLoad(&client);
222 pendingScript().releaseElementAndClear(); 227 pendingScript().releaseElementAndClear();
223 m_pendingScript = PendingScriptWrapper::create(); // This will destroy m_res ource. 228 m_pendingScript = PendingScriptWrapper::create(); // This will destroy m_res ource.
224 m_resource = 0; 229 m_resource = 0;
225 230
226 // The V8 side will complete too. This should not crash. We don't receive 231 // The V8 side will complete too. This should not crash. We don't receive
227 // any results from the streaming and the client doesn't get notified. 232 // any results from the streaming and the client doesn't get notified.
228 processTasksUntilStreamingComplete(); 233 processTasksUntilStreamingComplete();
229 EXPECT_FALSE(client.finished()); 234 EXPECT_FALSE(client.finished());
230 } 235 }
231 236
232 TEST_F(ScriptStreamingTest, SuppressingStreaming) 237 TEST_P(ScriptStreamingTest, SuppressingStreaming)
233 { 238 {
234 // If we notice during streaming that there is a code cache, streaming 239 // If we notice during streaming that there is a code cache, streaming
235 // is suppressed (V8 doesn't parse while the script is loading), and the 240 // is suppressed (V8 doesn't parse while the script is loading), and the
236 // upper layer (ScriptResourceClient) should get a notification when the 241 // upper layer (ScriptResourceClient) should get a notification when the
237 // script is loaded. 242 // script is loaded.
238 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking); 243 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking);
239 TestScriptResourceClient client; 244 TestScriptResourceClient client;
240 pendingScript().watchForLoad(&client); 245 pendingScript().watchForLoad(&client);
241 appendData("function foo() {"); 246 appendData("function foo() {");
242 appendPadding(); 247 appendPadding();
243 248
244 m_resource->setCachedMetadata(V8ScriptRunner::tagForCodeCache(), "X", 1, Res ource::CacheLocally); 249 m_resource->setCachedMetadata(V8ScriptRunner::tagForCodeCache(), "X", 1, Res ource::CacheLocally);
245 250
246 appendPadding(); 251 appendPadding();
247 finish(); 252 finish();
248 processTasksUntilStreamingComplete(); 253 processTasksUntilStreamingComplete();
249 EXPECT_TRUE(client.finished()); 254 EXPECT_TRUE(client.finished());
250 255
251 bool errorOccurred = false; 256 bool errorOccurred = false;
252 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre d); 257 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre d);
253 EXPECT_FALSE(errorOccurred); 258 EXPECT_FALSE(errorOccurred);
254 // ScriptSourceCode doesn't refer to the streamer, since we have suppressed 259 // ScriptSourceCode doesn't refer to the streamer, since we have suppressed
255 // the streaming and resumed the non-streaming code path for script 260 // the streaming and resumed the non-streaming code path for script
256 // compilation. 261 // compilation.
257 EXPECT_FALSE(sourceCode.streamer()); 262 EXPECT_FALSE(sourceCode.streamer());
258 } 263 }
259 264
260 TEST_F(ScriptStreamingTest, EmptyScripts) 265 TEST_P(ScriptStreamingTest, EmptyScripts)
261 { 266 {
262 // Empty scripts should also be streamed properly, that is, the upper layer 267 // Empty scripts should also be streamed properly, that is, the upper layer
263 // (ScriptResourceClient) should be notified when an empty script has been 268 // (ScriptResourceClient) should be notified when an empty script has been
264 // loaded. 269 // loaded.
265 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking); 270 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking);
266 TestScriptResourceClient client; 271 TestScriptResourceClient client;
267 pendingScript().watchForLoad(&client); 272 pendingScript().watchForLoad(&client);
268 273
269 // Finish the script without sending any data. 274 // Finish the script without sending any data.
270 finish(); 275 finish();
271 // The finished notification should arrive immediately and not be cycled 276 // The finished notification should arrive immediately and not be cycled
272 // through a background thread. 277 // through a background thread.
273 EXPECT_TRUE(client.finished()); 278 EXPECT_TRUE(client.finished());
274 279
275 bool errorOccurred = false; 280 bool errorOccurred = false;
276 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre d); 281 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre d);
277 EXPECT_FALSE(errorOccurred); 282 EXPECT_FALSE(errorOccurred);
278 EXPECT_FALSE(sourceCode.streamer()); 283 EXPECT_FALSE(sourceCode.streamer());
279 } 284 }
280 285
281 TEST_F(ScriptStreamingTest, SmallScripts) 286 TEST_P(ScriptStreamingTest, SmallScripts)
282 { 287 {
283 // Small scripts shouldn't be streamed. 288 // Small scripts shouldn't be streamed.
284 ScriptStreamer::setSmallScriptThresholdForTesting(100); 289 ScriptStreamer::setSmallScriptThresholdForTesting(100);
285 290
286 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking); 291 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking);
287 TestScriptResourceClient client; 292 TestScriptResourceClient client;
288 pendingScript().watchForLoad(&client); 293 pendingScript().watchForLoad(&client);
289 294
290 appendData("function foo() { }"); 295 appendData("function foo() { }");
291 296
292 finish(); 297 finish();
293 298
294 // The finished notification should arrive immediately and not be cycled 299 // The finished notification should arrive immediately and not be cycled
295 // through a background thread. 300 // through a background thread.
296 EXPECT_TRUE(client.finished()); 301 EXPECT_TRUE(client.finished());
297 302
298 bool errorOccurred = false; 303 bool errorOccurred = false;
299 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre d); 304 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre d);
300 EXPECT_FALSE(errorOccurred); 305 EXPECT_FALSE(errorOccurred);
301 EXPECT_FALSE(sourceCode.streamer()); 306 EXPECT_FALSE(sourceCode.streamer());
302 } 307 }
303 308
304 TEST_F(ScriptStreamingTest, ScriptsWithSmallFirstChunk) 309 TEST_P(ScriptStreamingTest, ScriptsWithSmallFirstChunk)
305 { 310 {
306 // If a script is long enough, if should be streamed, even if the first data 311 // If a script is long enough, if should be streamed, even if the first data
307 // chunk is small. 312 // chunk is small.
308 ScriptStreamer::setSmallScriptThresholdForTesting(100); 313 ScriptStreamer::setSmallScriptThresholdForTesting(100);
309 314
310 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking); 315 ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.sc riptState(), PendingScript::ParsingBlocking);
311 TestScriptResourceClient client; 316 TestScriptResourceClient client;
312 pendingScript().watchForLoad(&client); 317 pendingScript().watchForLoad(&client);
313 318
314 // This is the first data chunk which is small. 319 // This is the first data chunk which is small.
315 appendData("function foo() { }"); 320 appendData("function foo() { }");
316 appendPadding(); 321 appendPadding();
317 appendPadding(); 322 appendPadding();
318 appendPadding(); 323 appendPadding();
319 324
320 finish(); 325 finish();
321 326
322 processTasksUntilStreamingComplete(); 327 processTasksUntilStreamingComplete();
323 EXPECT_TRUE(client.finished()); 328 EXPECT_TRUE(client.finished());
324 bool errorOccurred = false; 329 bool errorOccurred = false;
325 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre d); 330 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre d);
326 EXPECT_FALSE(errorOccurred); 331 EXPECT_FALSE(errorOccurred);
327 EXPECT_TRUE(sourceCode.streamer()); 332 EXPECT_TRUE(sourceCode.streamer());
328 v8::TryCatch tryCatch; 333 v8::TryCatch tryCatch;
329 v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, is olate()); 334 v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, is olate());
330 EXPECT_FALSE(script.IsEmpty()); 335 EXPECT_FALSE(script.IsEmpty());
331 EXPECT_FALSE(tryCatch.HasCaught()); 336 EXPECT_FALSE(tryCatch.HasCaught());
332 } 337 }
333 338
339 INSTANTIATE_TEST_CASE_P(ScriptStreamingInstantiation, ScriptStreamingTest, ::tes ting::Values(false, true));
340
334 } // namespace 341 } // namespace
335 342
336 } // namespace blink 343 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698