OLD | NEW |
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 "core/html/parser/TextResourceDecoder.h" | 15 #include "core/html/parser/TextResourceDecoder.h" |
16 #include "platform/SharedBuffer.h" | 16 #include "platform/SharedBuffer.h" |
17 #include "platform/Task.h" | 17 #include "platform/Task.h" |
18 #include "platform/ThreadSafeFunctional.h" | 18 #include "platform/ThreadSafeFunctional.h" |
19 #include "platform/TraceEvent.h" | 19 #include "platform/TraceEvent.h" |
20 #include "public/platform/Platform.h" | 20 #include "public/platform/Platform.h" |
21 #include "public/platform/WebScheduler.h" | |
22 #include "wtf/MainThread.h" | 21 #include "wtf/MainThread.h" |
23 #include "wtf/text/TextEncodingRegistry.h" | 22 #include "wtf/text/TextEncodingRegistry.h" |
24 | 23 |
25 namespace blink { | 24 namespace blink { |
26 | 25 |
27 namespace { | 26 namespace { |
28 | 27 |
29 const char* startedStreamingHistogramName(PendingScript::Type scriptType) | 28 const char* startedStreamingHistogramName(PendingScript::Type scriptType) |
30 { | 29 { |
31 switch (scriptType) { | 30 switch (scriptType) { |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 }; | 155 }; |
157 | 156 |
158 | 157 |
159 // SourceStream implements the streaming interface towards V8. The main | 158 // SourceStream implements the streaming interface towards V8. The main |
160 // functionality is preparing the data to give to V8 on main thread, and | 159 // functionality is preparing the data to give to V8 on main thread, and |
161 // actually giving the data (via GetMoreData which is called on a background | 160 // actually giving the data (via GetMoreData which is called on a background |
162 // thread). | 161 // thread). |
163 class SourceStream : public v8::ScriptCompiler::ExternalSourceStream { | 162 class SourceStream : public v8::ScriptCompiler::ExternalSourceStream { |
164 WTF_MAKE_NONCOPYABLE(SourceStream); | 163 WTF_MAKE_NONCOPYABLE(SourceStream); |
165 public: | 164 public: |
166 explicit SourceStream(WebTaskRunner* loadingTaskRunner) | 165 SourceStream() |
167 : v8::ScriptCompiler::ExternalSourceStream() | 166 : v8::ScriptCompiler::ExternalSourceStream() |
168 , m_cancelled(false) | 167 , m_cancelled(false) |
169 , m_finished(false) | 168 , m_finished(false) |
170 , m_queueLeadPosition(0) | 169 , m_queueLeadPosition(0) |
171 , m_queueTailPosition(0) | 170 , m_queueTailPosition(0) |
172 , m_bookmarkPosition(0) | 171 , m_bookmarkPosition(0) |
173 , m_lengthOfBOM(0) | 172 , m_lengthOfBOM(0) |
174 , m_loadingTaskRunner(adoptPtr(loadingTaskRunner->clone())) | |
175 { | 173 { |
176 } | 174 } |
177 | 175 |
178 virtual ~SourceStream() override { } | 176 virtual ~SourceStream() override { } |
179 | 177 |
180 // Called by V8 on a background thread. Should block until we can return | 178 // Called by V8 on a background thread. Should block until we can return |
181 // some data. | 179 // some data. |
182 size_t GetMoreData(const uint8_t** src) override | 180 size_t GetMoreData(const uint8_t** src) override |
183 { | 181 { |
184 ASSERT(!isMainThread()); | 182 ASSERT(!isMainThread()); |
(...skipping 29 matching lines...) Expand all Loading... |
214 { | 212 { |
215 MutexLocker locker(m_mutex); | 213 MutexLocker locker(m_mutex); |
216 m_queueLeadPosition = m_bookmarkPosition; | 214 m_queueLeadPosition = m_bookmarkPosition; |
217 // See comments at m_lengthOfBOM declaration below for why | 215 // See comments at m_lengthOfBOM declaration below for why |
218 // we need this here. | 216 // we need this here. |
219 m_queueTailPosition = m_bookmarkPosition + m_lengthOfBOM; | 217 m_queueTailPosition = m_bookmarkPosition + m_lengthOfBOM; |
220 m_dataQueue.clear(); | 218 m_dataQueue.clear(); |
221 } | 219 } |
222 | 220 |
223 // Inform main thread to re-queue the data. | 221 // Inform main thread to re-queue the data. |
224 m_loadingTaskRunner->postTask( | 222 Platform::current()->mainThread()->taskRunner()->postTask( |
225 FROM_HERE, bind(&SourceStream::fetchDataFromResourceBuffer, this, 0)
); | 223 FROM_HERE, bind(&SourceStream::fetchDataFromResourceBuffer, this, 0)
); |
226 } | 224 } |
227 | 225 |
228 void didFinishLoading() | 226 void didFinishLoading() |
229 { | 227 { |
230 ASSERT(isMainThread()); | 228 ASSERT(isMainThread()); |
231 | 229 |
232 // ResetToBookmark may reset the data queue's 'finished' status, | 230 // ResetToBookmark may reset the data queue's 'finished' status, |
233 // so we may need to re-finish after a ResetToBookmark happened. | 231 // so we may need to re-finish after a ResetToBookmark happened. |
234 // We do this by remembering m_finished, and always checking for it | 232 // We do this by remembering m_finished, and always checking for it |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 // - m_queueLeadPosition counts the bytes that V8 has received | 363 // - m_queueLeadPosition counts the bytes that V8 has received |
366 // (i.e., without BOM) | 364 // (i.e., without BOM) |
367 // - m_queueTailPosition counts the bytes that Chrome has sent | 365 // - m_queueTailPosition counts the bytes that Chrome has sent |
368 // (i.e., with BOM) | 366 // (i.e., with BOM) |
369 // So when resetting the bookmark, we have to adjust the lead position | 367 // So when resetting the bookmark, we have to adjust the lead position |
370 // to account for the BOM (which happens implicitly in the regular | 368 // to account for the BOM (which happens implicitly in the regular |
371 // streaming case). | 369 // streaming case). |
372 // We store this separately, to avoid having to guard all | 370 // We store this separately, to avoid having to guard all |
373 // m_queueLeadPosition references with a mutex. | 371 // m_queueLeadPosition references with a mutex. |
374 unsigned m_lengthOfBOM; // Used by both threads; guarded by m_mutex. | 372 unsigned m_lengthOfBOM; // Used by both threads; guarded by m_mutex. |
375 | |
376 OwnPtr<WebTaskRunner> m_loadingTaskRunner; | |
377 }; | 373 }; |
378 | 374 |
379 size_t ScriptStreamer::kSmallScriptThreshold = 30 * 1024; | 375 size_t ScriptStreamer::kSmallScriptThreshold = 30 * 1024; |
380 | 376 |
381 void ScriptStreamer::startStreaming(PendingScript& script, PendingScript::Type s
criptType, Settings* settings, ScriptState* scriptState, WebTaskRunner* loadingT
askRunner) | 377 void ScriptStreamer::startStreaming(PendingScript& script, PendingScript::Type s
criptType, Settings* settings, ScriptState* scriptState) |
382 { | 378 { |
383 // We don't yet know whether the script will really be streamed. E.g., | 379 // We don't yet know whether the script will really be streamed. E.g., |
384 // suppressing streaming for short scripts is done later. Record only the | 380 // suppressing streaming for short scripts is done later. Record only the |
385 // sure negative cases here. | 381 // sure negative cases here. |
386 bool startedStreaming = startStreamingInternal(script, scriptType, settings,
scriptState, loadingTaskRunner); | 382 bool startedStreaming = startStreamingInternal(script, scriptType, settings,
scriptState); |
387 if (!startedStreaming) | 383 if (!startedStreaming) |
388 Platform::current()->histogramEnumeration(startedStreamingHistogramName(
scriptType), 0, 2); | 384 Platform::current()->histogramEnumeration(startedStreamingHistogramName(
scriptType), 0, 2); |
389 } | 385 } |
390 | 386 |
391 bool ScriptStreamer::convertEncoding(const char* encodingName, v8::ScriptCompile
r::StreamedSource::Encoding* encoding) | 387 bool ScriptStreamer::convertEncoding(const char* encodingName, v8::ScriptCompile
r::StreamedSource::Encoding* encoding) |
392 { | 388 { |
393 // Here's a list of encodings we can use for streaming. These are | 389 // Here's a list of encodings we can use for streaming. These are |
394 // the canonical names. | 390 // the canonical names. |
395 if (strcmp(encodingName, "windows-1252") == 0 | 391 if (strcmp(encodingName, "windows-1252") == 0 |
396 || strcmp(encodingName, "ISO-8859-1") == 0 | 392 || strcmp(encodingName, "ISO-8859-1") == 0 |
(...skipping 21 matching lines...) Expand all Loading... |
418 void ScriptStreamer::streamingCompleteOnBackgroundThread() | 414 void ScriptStreamer::streamingCompleteOnBackgroundThread() |
419 { | 415 { |
420 ASSERT(!isMainThread()); | 416 ASSERT(!isMainThread()); |
421 { | 417 { |
422 MutexLocker locker(m_mutex); | 418 MutexLocker locker(m_mutex); |
423 m_parsingFinished = true; | 419 m_parsingFinished = true; |
424 } | 420 } |
425 | 421 |
426 // notifyFinished might already be called, or it might be called in the | 422 // notifyFinished might already be called, or it might be called in the |
427 // future (if the parsing finishes earlier because of a parse error). | 423 // future (if the parsing finishes earlier because of a parse error). |
428 m_loadingTaskRunner->postTask(FROM_HERE, threadSafeBind(&ScriptStreamer::str
eamingComplete, AllowCrossThreadAccess(this))); | 424 Platform::current()->mainThread()->taskRunner()->postTask(FROM_HERE, threadS
afeBind(&ScriptStreamer::streamingComplete, AllowCrossThreadAccess(this))); |
429 | 425 |
430 // The task might delete ScriptStreamer, so it's not safe to do anything | 426 // The task might delete ScriptStreamer, so it's not safe to do anything |
431 // after posting it. Note that there's no way to guarantee that this | 427 // after posting it. Note that there's no way to guarantee that this |
432 // function has returned before the task is ran - however, we should not | 428 // function has returned before the task is ran - however, we should not |
433 // access the "this" object after posting the task. (Especially, we should | 429 // access the "this" object after posting the task. (Especially, we should |
434 // not be holding the mutex at this point.) | 430 // not be holding the mutex at this point.) |
435 } | 431 } |
436 | 432 |
437 void ScriptStreamer::cancel() | 433 void ScriptStreamer::cancel() |
438 { | 434 { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
510 | 506 |
511 if (!m_scriptState->contextIsValid()) { | 507 if (!m_scriptState->contextIsValid()) { |
512 suppressStreaming(); | 508 suppressStreaming(); |
513 Platform::current()->histogramEnumeration(notStreamingReasonHistogra
mName(m_scriptType), ContextNotValid, NotStreamingReasonEnd); | 509 Platform::current()->histogramEnumeration(notStreamingReasonHistogra
mName(m_scriptType), ContextNotValid, NotStreamingReasonEnd); |
514 Platform::current()->histogramEnumeration(startedStreamingHistogramN
ame(m_scriptType), 0, 2); | 510 Platform::current()->histogramEnumeration(startedStreamingHistogramN
ame(m_scriptType), 0, 2); |
515 return; | 511 return; |
516 } | 512 } |
517 | 513 |
518 ASSERT(!m_stream); | 514 ASSERT(!m_stream); |
519 ASSERT(!m_source); | 515 ASSERT(!m_source); |
520 m_stream = new SourceStream(m_loadingTaskRunner.get()); | 516 m_stream = new SourceStream(); |
521 // m_source takes ownership of m_stream. | 517 // m_source takes ownership of m_stream. |
522 m_source = adoptPtr(new v8::ScriptCompiler::StreamedSource(m_stream, m_e
ncoding)); | 518 m_source = adoptPtr(new v8::ScriptCompiler::StreamedSource(m_stream, m_e
ncoding)); |
523 | 519 |
524 ScriptState::Scope scope(m_scriptState.get()); | 520 ScriptState::Scope scope(m_scriptState.get()); |
525 WTF::OwnPtr<v8::ScriptCompiler::ScriptStreamingTask> scriptStreamingTask
(adoptPtr(v8::ScriptCompiler::StartStreamingScript(m_scriptState->isolate(), m_s
ource.get(), m_compileOptions))); | 521 WTF::OwnPtr<v8::ScriptCompiler::ScriptStreamingTask> scriptStreamingTask
(adoptPtr(v8::ScriptCompiler::StartStreamingScript(m_scriptState->isolate(), m_s
ource.get(), m_compileOptions))); |
526 if (!scriptStreamingTask) { | 522 if (!scriptStreamingTask) { |
527 // V8 cannot stream the script. | 523 // V8 cannot stream the script. |
528 suppressStreaming(); | 524 suppressStreaming(); |
529 m_stream = 0; | 525 m_stream = 0; |
530 m_source.clear(); | 526 m_source.clear(); |
(...skipping 30 matching lines...) Expand all Loading... |
561 m_stream->didFinishLoading(); | 557 m_stream->didFinishLoading(); |
562 m_loadingFinished = true; | 558 m_loadingFinished = true; |
563 | 559 |
564 // Calling notifyFinishedToClient can result into the upper layers dropping | 560 // Calling notifyFinishedToClient can result into the upper layers dropping |
565 // references to ScriptStreamer. Keep it alive until this function ends. | 561 // references to ScriptStreamer. Keep it alive until this function ends. |
566 RefPtrWillBeRawPtr<ScriptStreamer> protect(this); | 562 RefPtrWillBeRawPtr<ScriptStreamer> protect(this); |
567 | 563 |
568 notifyFinishedToClient(); | 564 notifyFinishedToClient(); |
569 } | 565 } |
570 | 566 |
571 ScriptStreamer::ScriptStreamer(ScriptResource* resource, PendingScript::Type scr
iptType, ScriptState* scriptState, v8::ScriptCompiler::CompileOptions compileOpt
ions, WebTaskRunner* loadingTaskRunner) | 567 ScriptStreamer::ScriptStreamer(ScriptResource* resource, PendingScript::Type scr
iptType, ScriptState* scriptState, v8::ScriptCompiler::CompileOptions compileOpt
ions) |
572 : m_resource(resource) | 568 : m_resource(resource) |
573 , m_detached(false) | 569 , m_detached(false) |
574 , m_stream(0) | 570 , m_stream(0) |
575 , m_client(0) | 571 , m_client(0) |
576 , m_loadingFinished(false) | 572 , m_loadingFinished(false) |
577 , m_parsingFinished(false) | 573 , m_parsingFinished(false) |
578 , m_haveEnoughDataForStreaming(false) | 574 , m_haveEnoughDataForStreaming(false) |
579 , m_streamingSuppressed(false) | 575 , m_streamingSuppressed(false) |
580 , m_compileOptions(compileOptions) | 576 , m_compileOptions(compileOptions) |
581 , m_scriptState(scriptState) | 577 , m_scriptState(scriptState) |
582 , m_scriptType(scriptType) | 578 , m_scriptType(scriptType) |
583 , m_encoding(v8::ScriptCompiler::StreamedSource::TWO_BYTE) // Unfortunately
there's no dummy encoding value in the enum; let's use one we don't stream. | 579 , m_encoding(v8::ScriptCompiler::StreamedSource::TWO_BYTE) // Unfortunately
there's no dummy encoding value in the enum; let's use one we don't stream. |
584 , m_loadingTaskRunner(adoptPtr(loadingTaskRunner->clone())) | |
585 { | 580 { |
586 } | 581 } |
587 | 582 |
588 ScriptStreamer::~ScriptStreamer() | 583 ScriptStreamer::~ScriptStreamer() |
589 { | 584 { |
590 } | 585 } |
591 | 586 |
592 DEFINE_TRACE(ScriptStreamer) | 587 DEFINE_TRACE(ScriptStreamer) |
593 { | 588 { |
594 visitor->trace(m_resource); | 589 visitor->trace(m_resource); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
630 // function calling notifyFinishedToClient was already scheduled in the task | 625 // function calling notifyFinishedToClient was already scheduled in the task |
631 // queue and the upper layer decided that it's not interested in the script | 626 // queue and the upper layer decided that it's not interested in the script |
632 // and called removeClient. | 627 // and called removeClient. |
633 if (!isFinished()) | 628 if (!isFinished()) |
634 return; | 629 return; |
635 | 630 |
636 if (m_client) | 631 if (m_client) |
637 m_client->notifyFinished(m_resource); | 632 m_client->notifyFinished(m_resource); |
638 } | 633 } |
639 | 634 |
640 bool ScriptStreamer::startStreamingInternal(PendingScript& script, PendingScript
::Type scriptType, Settings* settings, ScriptState* scriptState, WebTaskRunner*
loadingTaskRunner) | 635 bool ScriptStreamer::startStreamingInternal(PendingScript& script, PendingScript
::Type scriptType, Settings* settings, ScriptState* scriptState) |
641 { | 636 { |
642 ASSERT(isMainThread()); | 637 ASSERT(isMainThread()); |
643 ASSERT(scriptState->contextIsValid()); | 638 ASSERT(scriptState->contextIsValid()); |
644 ScriptResource* resource = script.resource(); | 639 ScriptResource* resource = script.resource(); |
645 if (resource->isLoaded()) { | 640 if (resource->isLoaded()) { |
646 Platform::current()->histogramEnumeration(notStreamingReasonHistogramNam
e(scriptType), AlreadyLoaded, NotStreamingReasonEnd); | 641 Platform::current()->histogramEnumeration(notStreamingReasonHistogramNam
e(scriptType), AlreadyLoaded, NotStreamingReasonEnd); |
647 return false; | 642 return false; |
648 } | 643 } |
649 if (!resource->url().protocolIsInHTTPFamily()) { | 644 if (!resource->url().protocolIsInHTTPFamily()) { |
650 Platform::current()->histogramEnumeration(notStreamingReasonHistogramNam
e(scriptType), NotHTTP, NotStreamingReasonEnd); | 645 Platform::current()->histogramEnumeration(notStreamingReasonHistogramNam
e(scriptType), NotHTTP, NotStreamingReasonEnd); |
(...skipping 12 matching lines...) Expand all Loading... |
663 | 658 |
664 // Decide what kind of cached data we should produce while streaming. Only | 659 // Decide what kind of cached data we should produce while streaming. Only |
665 // produce parser cache if the non-streaming compile takes advantage of it. | 660 // produce parser cache if the non-streaming compile takes advantage of it. |
666 v8::ScriptCompiler::CompileOptions compileOption = v8::ScriptCompiler::kNoCo
mpileOptions; | 661 v8::ScriptCompiler::CompileOptions compileOption = v8::ScriptCompiler::kNoCo
mpileOptions; |
667 if (settings->v8CacheOptions() == V8CacheOptionsParse) | 662 if (settings->v8CacheOptions() == V8CacheOptionsParse) |
668 compileOption = v8::ScriptCompiler::kProduceParserCache; | 663 compileOption = v8::ScriptCompiler::kProduceParserCache; |
669 | 664 |
670 // The Resource might go out of scope if the script is no longer | 665 // The Resource might go out of scope if the script is no longer |
671 // needed. This makes PendingScript notify the ScriptStreamer when it is | 666 // needed. This makes PendingScript notify the ScriptStreamer when it is |
672 // destroyed. | 667 // destroyed. |
673 script.setStreamer(ScriptStreamer::create(resource, scriptType, scriptState,
compileOption, loadingTaskRunner)); | 668 script.setStreamer(ScriptStreamer::create(resource, scriptType, scriptState,
compileOption)); |
674 | 669 |
675 return true; | 670 return true; |
676 } | 671 } |
677 | 672 |
678 } // namespace blink | 673 } // namespace blink |
OLD | NEW |