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