| 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 "bindings/core/v8/ScriptStreamer.h" | 5 #include "bindings/core/v8/ScriptStreamer.h" |
| 6 | 6 |
| 7 #include "bindings/core/v8/ScriptStreamerThread.h" | 7 #include "bindings/core/v8/ScriptStreamerThread.h" |
| 8 #include "bindings/core/v8/V8ScriptRunner.h" | 8 #include "bindings/core/v8/V8ScriptRunner.h" |
| 9 #include "core/dom/Document.h" | 9 #include "core/dom/Document.h" |
| 10 #include "core/dom/Element.h" | 10 #include "core/dom/Element.h" |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 } | 290 } |
| 291 | 291 |
| 292 void fetchDataFromResourceBuffer(size_t lengthOfBOM) | 292 void fetchDataFromResourceBuffer(size_t lengthOfBOM) |
| 293 { | 293 { |
| 294 ASSERT(isMainThread()); | 294 ASSERT(isMainThread()); |
| 295 MutexLocker locker(m_mutex); // For m_cancelled + m_queueTailPosition. | 295 MutexLocker locker(m_mutex); // For m_cancelled + m_queueTailPosition. |
| 296 | 296 |
| 297 // Get as much data from the ResourceBuffer as we can. | 297 // Get as much data from the ResourceBuffer as we can. |
| 298 const char* data = 0; | 298 const char* data = 0; |
| 299 Vector<const char*> chunks; | 299 Vector<const char*> chunks; |
| 300 Vector<unsigned> chunkLengths; | 300 Vector<size_t> chunkLengths; |
| 301 size_t dataLength = 0; | 301 size_t dataLength = 0; |
| 302 | 302 |
| 303 if (!m_cancelled) { | 303 if (!m_cancelled) { |
| 304 while (unsigned length = m_resourceBuffer->getSomeData(data, m_queue
TailPosition)) { | 304 while (size_t length = m_resourceBuffer->getSomeData(data, m_queueTa
ilPosition)) { |
| 305 // FIXME: Here we can limit based on the total length, if it tur
ns | 305 // FIXME: Here we can limit based on the total length, if it tur
ns |
| 306 // out that we don't want to give all the data we have (memory | 306 // out that we don't want to give all the data we have (memory |
| 307 // vs. speed). | 307 // vs. speed). |
| 308 chunks.append(data); | 308 chunks.append(data); |
| 309 chunkLengths.append(length); | 309 chunkLengths.append(length); |
| 310 dataLength += length; | 310 dataLength += length; |
| 311 m_queueTailPosition += length; | 311 m_queueTailPosition += length; |
| 312 } | 312 } |
| 313 } | 313 } |
| 314 | 314 |
| 315 if (lengthOfBOM > 0) { | 315 if (lengthOfBOM > 0) { |
| 316 ASSERT(!m_lengthOfBOM); // There should be only one BOM. | 316 ASSERT(!m_lengthOfBOM); // There should be only one BOM. |
| 317 m_lengthOfBOM = lengthOfBOM; | 317 m_lengthOfBOM = lengthOfBOM; |
| 318 } | 318 } |
| 319 | 319 |
| 320 // Copy the data chunks into a new buffer, since we're going to give the | 320 // Copy the data chunks into a new buffer, since we're going to give the |
| 321 // data to a background thread. | 321 // data to a background thread. |
| 322 if (dataLength > lengthOfBOM) { | 322 if (dataLength > lengthOfBOM) { |
| 323 dataLength -= lengthOfBOM; | 323 dataLength -= lengthOfBOM; |
| 324 uint8_t* copiedData = new uint8_t[dataLength]; | 324 uint8_t* copiedData = new uint8_t[dataLength]; |
| 325 unsigned offset = 0; | 325 size_t offset = 0; |
| 326 for (size_t i = 0; i < chunks.size(); ++i) { | 326 for (size_t i = 0; i < chunks.size(); ++i) { |
| 327 memcpy(copiedData + offset, chunks[i] + lengthOfBOM, chunkLength
s[i] - lengthOfBOM); | 327 memcpy(copiedData + offset, chunks[i] + lengthOfBOM, chunkLength
s[i] - lengthOfBOM); |
| 328 offset += chunkLengths[i] - lengthOfBOM; | 328 offset += chunkLengths[i] - lengthOfBOM; |
| 329 // BOM is only in the first chunk | 329 // BOM is only in the first chunk |
| 330 lengthOfBOM = 0; | 330 lengthOfBOM = 0; |
| 331 } | 331 } |
| 332 m_dataQueue.produce(copiedData, dataLength); | 332 m_dataQueue.produce(copiedData, dataLength); |
| 333 } | 333 } |
| 334 | 334 |
| 335 if (m_finished || m_cancelled) | 335 if (m_finished || m_cancelled) |
| 336 m_dataQueue.finish(); | 336 m_dataQueue.finish(); |
| 337 } | 337 } |
| 338 | 338 |
| 339 // For coordinating between the main thread and background thread tasks. | 339 // For coordinating between the main thread and background thread tasks. |
| 340 // Guards m_cancelled and m_queueTailPosition. | 340 // Guards m_cancelled and m_queueTailPosition. |
| 341 Mutex m_mutex; | 341 Mutex m_mutex; |
| 342 | 342 |
| 343 // The shared buffer containing the resource data + state variables. | 343 // The shared buffer containing the resource data + state variables. |
| 344 // Used by both threads, guarded by m_mutex. | 344 // Used by both threads, guarded by m_mutex. |
| 345 bool m_cancelled; | 345 bool m_cancelled; |
| 346 bool m_finished; | 346 bool m_finished; |
| 347 | 347 |
| 348 RefPtr<SharedBuffer> m_resourceBuffer; // Only used by the main thread. | 348 RefPtr<SharedBuffer> m_resourceBuffer; // Only used by the main thread. |
| 349 | 349 |
| 350 // The queue contains the data to be passed to the V8 thread. | 350 // The queue contains the data to be passed to the V8 thread. |
| 351 // queueLeadPosition: data we have handed off to the V8 thread. | 351 // queueLeadPosition: data we have handed off to the V8 thread. |
| 352 // queueTailPosition: end of data we have enqued in the queue. | 352 // queueTailPosition: end of data we have enqued in the queue. |
| 353 // bookmarkPosition: position of the bookmark. | 353 // bookmarkPosition: position of the bookmark. |
| 354 SourceStreamDataQueue m_dataQueue; // Thread safe. | 354 SourceStreamDataQueue m_dataQueue; // Thread safe. |
| 355 unsigned m_queueLeadPosition; // Only used by v8 thread. | 355 size_t m_queueLeadPosition; // Only used by v8 thread. |
| 356 unsigned m_queueTailPosition; // Used by both threads; guarded by m_mutex. | 356 size_t m_queueTailPosition; // Used by both threads; guarded by m_mutex. |
| 357 unsigned m_bookmarkPosition; // Only used by v8 thread. | 357 size_t m_bookmarkPosition; // Only used by v8 thread. |
| 358 | 358 |
| 359 // BOM (Unicode Byte Order Mark) handling: | 359 // BOM (Unicode Byte Order Mark) handling: |
| 360 // This class is responsible for stripping out the BOM, since Chrome | 360 // This class is responsible for stripping out the BOM, since Chrome |
| 361 // delivers the input stream potentially with BOM, but V8 doesn't want | 361 // delivers the input stream potentially with BOM, but V8 doesn't want |
| 362 // to see the BOM. This is mostly easy to do, except for a funky edge | 362 // to see the BOM. This is mostly easy to do, except for a funky edge |
| 363 // condition with bookmarking: | 363 // condition with bookmarking: |
| 364 // - m_queueLeadPosition counts the bytes that V8 has received | 364 // - m_queueLeadPosition counts the bytes that V8 has received |
| 365 // (i.e., without BOM) | 365 // (i.e., without BOM) |
| 366 // - m_queueTailPosition counts the bytes that Chrome has sent | 366 // - m_queueTailPosition counts the bytes that Chrome has sent |
| 367 // (i.e., with BOM) | 367 // (i.e., with BOM) |
| 368 // So when resetting the bookmark, we have to adjust the lead position | 368 // So when resetting the bookmark, we have to adjust the lead position |
| 369 // to account for the BOM (which happens implicitly in the regular | 369 // to account for the BOM (which happens implicitly in the regular |
| 370 // streaming case). | 370 // streaming case). |
| 371 // We store this separately, to avoid having to guard all | 371 // We store this separately, to avoid having to guard all |
| 372 // m_queueLeadPosition references with a mutex. | 372 // m_queueLeadPosition references with a mutex. |
| 373 unsigned m_lengthOfBOM; // Used by both threads; guarded by m_mutex. | 373 size_t m_lengthOfBOM; // Used by both threads; guarded by m_mutex. |
| 374 | 374 |
| 375 OwnPtr<WebTaskRunner> m_loadingTaskRunner; | 375 OwnPtr<WebTaskRunner> m_loadingTaskRunner; |
| 376 }; | 376 }; |
| 377 | 377 |
| 378 size_t ScriptStreamer::kSmallScriptThreshold = 30 * 1024; | 378 size_t ScriptStreamer::kSmallScriptThreshold = 30 * 1024; |
| 379 | 379 |
| 380 void ScriptStreamer::startStreaming(PendingScript& script, PendingScript::Type s
criptType, Settings* settings, ScriptState* scriptState, WebTaskRunner* loadingT
askRunner) | 380 void ScriptStreamer::startStreaming(PendingScript& script, PendingScript::Type s
criptType, Settings* settings, ScriptState* scriptState, WebTaskRunner* loadingT
askRunner) |
| 381 { | 381 { |
| 382 // We don't yet know whether the script will really be streamed. E.g., | 382 // We don't yet know whether the script will really be streamed. E.g., |
| 383 // suppressing streaming for short scripts is done later. Record only the | 383 // suppressing streaming for short scripts is done later. Record only the |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 | 476 |
| 477 // Encoding should be detected only when we have some data. It's | 477 // Encoding should be detected only when we have some data. It's |
| 478 // possible that resource->encoding() returns a different encoding | 478 // possible that resource->encoding() returns a different encoding |
| 479 // before the loading has started and after we got some data. In | 479 // before the loading has started and after we got some data. In |
| 480 // addition, check for byte order marks. Note that checking the byte | 480 // addition, check for byte order marks. Note that checking the byte |
| 481 // order mark might change the encoding. We cannot decode the full text | 481 // order mark might change the encoding. We cannot decode the full text |
| 482 // here, because it might contain incomplete UTF-8 characters. Also note | 482 // here, because it might contain incomplete UTF-8 characters. Also note |
| 483 // that have at least kSmallScriptThreshold worth of data, which is more | 483 // that have at least kSmallScriptThreshold worth of data, which is more |
| 484 // than enough for detecting a BOM. | 484 // than enough for detecting a BOM. |
| 485 const char* data = 0; | 485 const char* data = 0; |
| 486 unsigned length = resource->resourceBuffer()->getSomeData(data, 0); | 486 size_t length = resource->resourceBuffer()->getSomeData(data, static_cas
t<size_t>(0)); |
| 487 | 487 |
| 488 OwnPtr<TextResourceDecoder> decoder(TextResourceDecoder::create("applica
tion/javascript", resource->encoding())); | 488 OwnPtr<TextResourceDecoder> decoder(TextResourceDecoder::create("applica
tion/javascript", resource->encoding())); |
| 489 lengthOfBOM = decoder->checkForBOM(data, length); | 489 lengthOfBOM = decoder->checkForBOM(data, length); |
| 490 | 490 |
| 491 // Maybe the encoding changed because we saw the BOM; get the encoding | 491 // Maybe the encoding changed because we saw the BOM; get the encoding |
| 492 // from the decoder. | 492 // from the decoder. |
| 493 if (!convertEncoding(decoder->encoding().name(), &m_encoding)) { | 493 if (!convertEncoding(decoder->encoding().name(), &m_encoding)) { |
| 494 suppressStreaming(); | 494 suppressStreaming(); |
| 495 Platform::current()->histogramEnumeration(notStreamingReasonHistogra
mName(m_scriptType), EncodingNotSupported, NotStreamingReasonEnd); | 495 Platform::current()->histogramEnumeration(notStreamingReasonHistogra
mName(m_scriptType), EncodingNotSupported, NotStreamingReasonEnd); |
| 496 Platform::current()->histogramEnumeration(startedStreamingHistogramN
ame(m_scriptType), 0, 2); | 496 Platform::current()->histogramEnumeration(startedStreamingHistogramN
ame(m_scriptType), 0, 2); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 668 | 668 |
| 669 // The Resource might go out of scope if the script is no longer | 669 // The Resource might go out of scope if the script is no longer |
| 670 // needed. This makes PendingScript notify the ScriptStreamer when it is | 670 // needed. This makes PendingScript notify the ScriptStreamer when it is |
| 671 // destroyed. | 671 // destroyed. |
| 672 script.setStreamer(ScriptStreamer::create(resource, scriptType, scriptState,
compileOption, loadingTaskRunner)); | 672 script.setStreamer(ScriptStreamer::create(resource, scriptType, scriptState,
compileOption, loadingTaskRunner)); |
| 673 | 673 |
| 674 return true; | 674 return true; |
| 675 } | 675 } |
| 676 | 676 |
| 677 } // namespace blink | 677 } // namespace blink |
| OLD | NEW |