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

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

Issue 680493002: Revert "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: 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 #include "config.h" 5 #include "config.h"
6 #include "bindings/core/v8/ScriptStreamer.h" 6 #include "bindings/core/v8/ScriptStreamer.h"
7 7
8 #include "bindings/core/v8/ScriptStreamerThread.h" 8 #include "bindings/core/v8/ScriptStreamerThread.h"
9 #include "bindings/core/v8/V8ScriptRunner.h" 9 #include "bindings/core/v8/V8ScriptRunner.h"
10 #include "core/dom/Document.h" 10 #include "core/dom/Document.h"
11 #include "core/dom/Element.h" 11 #include "core/dom/Element.h"
12 #include "core/dom/PendingScript.h" 12 #include "core/dom/PendingScript.h"
13 #include "core/fetch/ScriptResource.h" 13 #include "core/fetch/ScriptResource.h"
14 #include "core/frame/Settings.h" 14 #include "core/frame/Settings.h"
15 #include "platform/SharedBuffer.h" 15 #include "platform/SharedBuffer.h"
16 #include "platform/TraceEvent.h"
17 #include "public/platform/Platform.h" 16 #include "public/platform/Platform.h"
18 #include "wtf/MainThread.h" 17 #include "wtf/MainThread.h"
19 #include "wtf/text/TextEncodingRegistry.h" 18 #include "wtf/text/TextEncodingRegistry.h"
20 19
21 namespace blink { 20 namespace blink {
22 21
23 // For passing data between the main thread (producer) and the streamer thread 22 // For passing data between the main thread (producer) and the streamer thread
24 // (consumer). The main thread prepares the data (copies it from Resource) and 23 // (consumer). The main thread prepares the data (copies it from Resource) and
25 // the streamer thread feeds it to V8. 24 // the streamer thread feeds it to V8.
26 class SourceStreamDataQueue { 25 class SourceStreamDataQueue {
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 void ScriptStreamer::startStreaming(PendingScript& script, Settings* settings, S criptState* scriptState, PendingScript::Type scriptType) 217 void ScriptStreamer::startStreaming(PendingScript& script, Settings* settings, S criptState* scriptState, PendingScript::Type scriptType)
219 { 218 {
220 // We don't yet know whether the script will really be streamed. E.g., 219 // We don't yet know whether the script will really be streamed. E.g.,
221 // suppressing streaming for short scripts is done later. Record only the 220 // suppressing streaming for short scripts is done later. Record only the
222 // sure negative cases here. 221 // sure negative cases here.
223 bool startedStreaming = startStreamingInternal(script, settings, scriptState , scriptType); 222 bool startedStreaming = startStreamingInternal(script, settings, scriptState , scriptType);
224 if (!startedStreaming) 223 if (!startedStreaming)
225 blink::Platform::current()->histogramEnumeration(startedStreamingHistogr amName(scriptType), 0, 2); 224 blink::Platform::current()->histogramEnumeration(startedStreamingHistogr amName(scriptType), 0, 2);
226 } 225 }
227 226
228 void ScriptStreamer::streamingCompleteOnBackgroundThread() 227 void ScriptStreamer::streamingComplete()
229 { 228 {
230 ASSERT(!isMainThread()); 229 ASSERT(isMainThread());
231 MutexLocker locker(m_mutex); 230 // It's possible that the corresponding Resource was deleted before V8
231 // finished streaming. In that case, the data or the notification is not
232 // needed. In addition, if the streaming is suppressed, the non-streaming
233 // code path will resume after the resource has loaded, before the
234 // background task finishes.
235 if (m_detached || m_streamingSuppressed) {
236 deref();
237 return;
238 }
239
240 // We have now streamed the whole script to V8 and it has parsed the
241 // script. We're ready for the next step: compiling and executing the
242 // script.
232 m_parsingFinished = true; 243 m_parsingFinished = true;
233 if (shouldBlockMainThread()) { 244
234 // Normally, the main thread is waiting at this point, but it can also 245 notifyFinishedToClient();
235 // happen that the load is not yet finished (e.g., a parse error). In 246
236 // that case, notifyFinished will be called eventually and it will not 247 // The background thread no longer holds an implicit reference.
237 // wait on m_parsingFinishedCondition. 248 deref();
238 m_parsingFinishedCondition.signal();
239 } else {
240 callOnMainThread(WTF::bind(&ScriptStreamer::streamingComplete, this));
241 }
242 } 249 }
243 250
244 void ScriptStreamer::cancel() 251 void ScriptStreamer::cancel()
245 { 252 {
246 ASSERT(isMainThread()); 253 ASSERT(isMainThread());
247 // The upper layer doesn't need the script any more, but streaming might 254 // The upper layer doesn't need the script any more, but streaming might
248 // still be ongoing. Tell SourceStream to try to cancel it whenever it gets 255 // still be ongoing. Tell SourceStream to try to cancel it whenever it gets
249 // the control the next time. It can also be that V8 has already completed 256 // the control the next time. It can also be that V8 has already completed
250 // its operations and streamingComplete will be called soon. 257 // its operations and streamingComplete will be called soon.
251 m_detached = true; 258 m_detached = true;
252 m_resource = 0; 259 m_resource = 0;
253 m_stream->cancel(); 260 m_stream->cancel();
254 } 261 }
255 262
256 void ScriptStreamer::suppressStreaming() 263 void ScriptStreamer::suppressStreaming()
257 { 264 {
258 MutexLocker locker(m_mutex);
259 ASSERT(!m_parsingFinished); 265 ASSERT(!m_parsingFinished);
260 ASSERT(!m_loadingFinished); 266 ASSERT(!m_loadingFinished);
261 m_streamingSuppressed = true; 267 m_streamingSuppressed = true;
262 } 268 }
263 269
264 void ScriptStreamer::notifyAppendData(ScriptResource* resource) 270 void ScriptStreamer::notifyAppendData(ScriptResource* resource)
265 { 271 {
266 ASSERT(isMainThread()); 272 ASSERT(isMainThread());
267 ASSERT(m_resource == resource); 273 ASSERT(m_resource == resource);
268 if (m_streamingSuppressed) 274 if (m_streamingSuppressed)
(...skipping 12 matching lines...) Expand all
281 // new task shouldn't be queued before the running task completes, 287 // new task shouldn't be queued before the running task completes,
282 // because the running task can block and wait for data from the 288 // because the running task can block and wait for data from the
283 // network. 289 // network.
284 suppressStreaming(); 290 suppressStreaming();
285 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2 ); 291 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2 );
286 return; 292 return;
287 } 293 }
288 ASSERT(m_task); 294 ASSERT(m_task);
289 // ScriptStreamer needs to stay alive as long as the background task is 295 // ScriptStreamer needs to stay alive as long as the background task is
290 // running. This is taken care of with a manual ref() & deref() pair; 296 // running. This is taken care of with a manual ref() & deref() pair;
291 // the corresponding deref() is in streamingComplete or in 297 // the corresponding deref() is in streamingComplete.
292 // notifyFinished.
293 ref(); 298 ref();
294 ScriptStreamingTask* task = new ScriptStreamingTask(m_task.release(), th is); 299 ScriptStreamingTask* task = new ScriptStreamingTask(m_task.release(), th is);
295 ScriptStreamerThread::shared()->postTask(task); 300 ScriptStreamerThread::shared()->postTask(task);
296 blink::Platform::current()->histogramEnumeration(histogramName, 1, 2); 301 blink::Platform::current()->histogramEnumeration(histogramName, 1, 2);
297 } 302 }
298 m_stream->didReceiveData(); 303 m_stream->didReceiveData();
299 } 304 }
300 305
301 void ScriptStreamer::notifyFinished(Resource* resource) 306 void ScriptStreamer::notifyFinished(Resource* resource)
302 { 307 {
303 ASSERT(isMainThread()); 308 ASSERT(isMainThread());
304 ASSERT(m_resource == resource); 309 ASSERT(m_resource == resource);
305 // A special case: empty and small scripts. We didn't receive enough data to 310 // A special case: empty and small scripts. We didn't receive enough data to
306 // start the streaming before this notification. In that case, there won't 311 // start the streaming before this notification. In that case, there won't
307 // be a "parsing complete" notification either, and we should not wait for 312 // be a "parsing complete" notification either, and we should not wait for
308 // it. 313 // it.
309 if (!m_haveEnoughDataForStreaming) { 314 if (!m_haveEnoughDataForStreaming) {
310 const char* histogramName = startedStreamingHistogramName(m_scriptType); 315 const char* histogramName = startedStreamingHistogramName(m_scriptType);
311 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2); 316 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2);
312 suppressStreaming(); 317 suppressStreaming();
313 } 318 }
314 m_stream->didFinishLoading(); 319 m_stream->didFinishLoading();
315 m_loadingFinished = true; 320 m_loadingFinished = true;
316
317 if (shouldBlockMainThread()) {
318 // Make the main thead wait until the streaming is complete, to make
319 // sure that the script gets the main thread's attention as early as
320 // possible (for possible compiling, if the client wants to do it
321 // right away). Note that blocking here is not any worse than the
322 // non-streaming code path where the main thread eventually blocks
323 // to parse the script.
324 TRACE_EVENT0("v8", "v8.mainThreadWaitingForParserThread");
325 MutexLocker locker(m_mutex);
326 if (!isFinished()) {
327 m_parsingFinishedCondition.wait(m_mutex);
328 }
329 ASSERT(isFinished());
330 }
331
332 notifyFinishedToClient(); 321 notifyFinishedToClient();
333
334 if (shouldBlockMainThread() && m_parsingFinished) {
335 // streamingComplete won't be called, so do the ramp-down work
336 // here. Since m_parsingFinished is true, we know that there was a
337 // background task and we need to deref().
338 deref();
339 }
340 } 322 }
341 323
342 ScriptStreamer::ScriptStreamer(ScriptResource* resource, v8::ScriptCompiler::Str eamedSource::Encoding encoding, PendingScript::Type scriptType, ScriptStreamingM ode mode) 324 ScriptStreamer::ScriptStreamer(ScriptResource* resource, v8::ScriptCompiler::Str eamedSource::Encoding encoding, PendingScript::Type scriptType)
343 : m_resource(resource) 325 : m_resource(resource)
344 , m_detached(false) 326 , m_detached(false)
345 , m_stream(new SourceStream(this)) 327 , m_stream(new SourceStream(this))
346 , m_source(m_stream, encoding) // m_source takes ownership of m_stream. 328 , m_source(m_stream, encoding) // m_source takes ownership of m_stream.
347 , m_client(0) 329 , m_client(0)
348 , m_loadingFinished(false) 330 , m_loadingFinished(false)
349 , m_parsingFinished(false) 331 , m_parsingFinished(false)
350 , m_haveEnoughDataForStreaming(false) 332 , m_haveEnoughDataForStreaming(false)
351 , m_streamingSuppressed(false) 333 , m_streamingSuppressed(false)
352 , m_scriptType(scriptType) 334 , m_scriptType(scriptType)
353 , m_scriptStreamingMode(mode)
354 { 335 {
355 } 336 }
356 337
357 void ScriptStreamer::streamingComplete()
358 {
359 // The background task is completed; do the necessary ramp-down in the main
360 // thread.
361 ASSERT(isMainThread());
362 // In the blocking mode, the ramp-down is done in notifyFinished.
363 ASSERT(!shouldBlockMainThread());
364
365 // It's possible that the corresponding Resource was deleted before V8
366 // finished streaming. In that case, the data or the notification is not
367 // needed. In addition, if the streaming is suppressed, the non-streaming
368 // code path will resume after the resource has loaded, before the
369 // background task finishes.
370 if (m_detached || m_streamingSuppressed) {
371 deref();
372 return;
373 }
374
375 // We have now streamed the whole script to V8 and it has parsed the
376 // script. We're ready for the next step: compiling and executing the
377 // script.
378 notifyFinishedToClient();
379
380 // The background thread no longer holds an implicit reference.
381 deref();
382 }
383
384 void ScriptStreamer::notifyFinishedToClient() 338 void ScriptStreamer::notifyFinishedToClient()
385 { 339 {
386 ASSERT(isMainThread()); 340 ASSERT(isMainThread());
387 // Usually, the loading will be finished first, and V8 will still need some 341 // Usually, the loading will be finished first, and V8 will still need some
388 // time to catch up. But the other way is possible too: if V8 detects a 342 // time to catch up. But the other way is possible too: if V8 detects a
389 // parse error, the V8 side can complete before loading has finished. Send 343 // parse error, the V8 side can complete before loading has finished. Send
390 // the notification after both loading and V8 side operations have 344 // the notification after both loading and V8 side operations have
391 // completed. Here we also check that we have a client: it can happen that a 345 // completed. Here we also check that we have a client: it can happen that a
392 // function calling notifyFinishedToClient was already scheduled in the task 346 // function calling notifyFinishedToClient was already scheduled in the task
393 // queue and the upper layer decided that it's not interested in the script 347 // queue and the upper layer decided that it's not interested in the script
394 // and called removeClient. 348 // and called removeClient.
395 MutexLocker locker(m_mutex);
396 if (isFinished() && m_client) 349 if (isFinished() && m_client)
397 m_client->notifyFinished(m_resource); 350 m_client->notifyFinished(m_resource);
398 } 351 }
399 352
400 const char* ScriptStreamer::startedStreamingHistogramName(PendingScript::Type sc riptType) 353 const char* ScriptStreamer::startedStreamingHistogramName(PendingScript::Type sc riptType)
401 { 354 {
402 switch (scriptType) { 355 switch (scriptType) {
403 case PendingScript::ParsingBlocking: 356 case PendingScript::ParsingBlocking:
404 return "WebCore.Scripts.ParsingBlocking.StartedStreaming"; 357 return "WebCore.Scripts.ParsingBlocking.StartedStreaming";
405 break; 358 break;
406 case PendingScript::Deferred: 359 case PendingScript::Deferred:
407 return "WebCore.Scripts.Deferred.StartedStreaming"; 360 return "WebCore.Scripts.Deferred.StartedStreaming";
408 break; 361 break;
409 case PendingScript::Async: 362 case PendingScript::Async:
410 return "WebCore.Scripts.Async.StartedStreaming"; 363 return "WebCore.Scripts.Async.StartedStreaming";
411 break; 364 break;
412 default: 365 default:
413 ASSERT_NOT_REACHED(); 366 ASSERT_NOT_REACHED();
414 break; 367 break;
415 } 368 }
416 return 0; 369 return 0;
417 } 370 }
418 371
419 bool ScriptStreamer::startStreamingInternal(PendingScript& script, Settings* set tings, ScriptState* scriptState, PendingScript::Type scriptType) 372 bool ScriptStreamer::startStreamingInternal(PendingScript& script, Settings* set tings, ScriptState* scriptState, PendingScript::Type scriptType)
420 { 373 {
421 ASSERT(isMainThread()); 374 ASSERT(isMainThread());
422 if (!settings || !settings->v8ScriptStreamingEnabled()) 375 if (!settings || !settings->v8ScriptStreamingEnabled())
423 return false; 376 return false;
424 if (settings->v8ScriptStreamingMode() == ScriptStreamingModeOnlyAsyncAndDefe r
425 && scriptType == PendingScript::ParsingBlocking)
426 return false;
427
428 ScriptResource* resource = script.resource(); 377 ScriptResource* resource = script.resource();
429 ASSERT(!resource->isLoaded()); 378 ASSERT(!resource->isLoaded());
430 if (!resource->url().protocolIsInHTTPFamily()) 379 if (!resource->url().protocolIsInHTTPFamily())
431 return false; 380 return false;
432 if (resource->resourceToRevalidate()) { 381 if (resource->resourceToRevalidate()) {
433 // This happens e.g., during reloads. We're actually not going to load 382 // This happens e.g., during reloads. We're actually not going to load
434 // the current Resource of the PendingScript but switch to another 383 // the current Resource of the PendingScript but switch to another
435 // Resource -> don't stream. 384 // Resource -> don't stream.
436 return false; 385 return false;
437 } 386 }
(...skipping 21 matching lines...) Expand all
459 return false; 408 return false;
460 } 409 }
461 410
462 if (!scriptState->contextIsValid()) 411 if (!scriptState->contextIsValid())
463 return false; 412 return false;
464 ScriptState::Scope scope(scriptState); 413 ScriptState::Scope scope(scriptState);
465 414
466 // The Resource might go out of scope if the script is no longer needed. We 415 // The Resource might go out of scope if the script is no longer needed. We
467 // will soon call PendingScript::setStreamer, which makes the PendingScript 416 // will soon call PendingScript::setStreamer, which makes the PendingScript
468 // notify the ScriptStreamer when it is destroyed. 417 // notify the ScriptStreamer when it is destroyed.
469 RefPtr<ScriptStreamer> streamer = adoptRef(new ScriptStreamer(resource, enco ding, scriptType, settings->v8ScriptStreamingMode())); 418 RefPtr<ScriptStreamer> streamer = adoptRef(new ScriptStreamer(resource, enco ding, scriptType));
470 419
471 // Decide what kind of cached data we should produce while streaming. By 420 // Decide what kind of cached data we should produce while streaming. By
472 // default, we generate the parser cache for streamed scripts, to emulate 421 // default, we generate the parser cache for streamed scripts, to emulate
473 // the non-streaming behavior (see V8ScriptRunner::compileScript). 422 // the non-streaming behavior (see V8ScriptRunner::compileScript).
474 v8::ScriptCompiler::CompileOptions compileOption = v8::ScriptCompiler::kProd uceParserCache; 423 v8::ScriptCompiler::CompileOptions compileOption = v8::ScriptCompiler::kProd uceParserCache;
475 if (settings->v8CacheOptions() == V8CacheOptionsCode) 424 if (settings->v8CacheOptions() == V8CacheOptionsCode)
476 compileOption = v8::ScriptCompiler::kProduceCodeCache; 425 compileOption = v8::ScriptCompiler::kProduceCodeCache;
477 v8::ScriptCompiler::ScriptStreamingTask* scriptStreamingTask = v8::ScriptCom piler::StartStreamingScript(scriptState->isolate(), &(streamer->m_source), compi leOption); 426 v8::ScriptCompiler::ScriptStreamingTask* scriptStreamingTask = v8::ScriptCom piler::StartStreamingScript(scriptState->isolate(), &(streamer->m_source), compi leOption);
478 if (scriptStreamingTask) { 427 if (scriptStreamingTask) {
479 streamer->m_task = adoptPtr(scriptStreamingTask); 428 streamer->m_task = adoptPtr(scriptStreamingTask);
480 script.setStreamer(streamer.release()); 429 script.setStreamer(streamer.release());
481 return true; 430 return true;
482 } 431 }
483 // Otherwise, V8 cannot stream the script. 432 // Otherwise, V8 cannot stream the script.
484 return false; 433 return false;
485 } 434 }
486 435
487 } // namespace blink 436 } // namespace blink
OLDNEW
« no previous file with comments | « Source/bindings/core/v8/ScriptStreamer.h ('k') | Source/bindings/core/v8/ScriptStreamerTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698