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" |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
246 | 246 |
247 void ScriptStreamer::cancel() | 247 void ScriptStreamer::cancel() |
248 { | 248 { |
249 ASSERT(isMainThread()); | 249 ASSERT(isMainThread()); |
250 // The upper layer doesn't need the script any more, but streaming might | 250 // The upper layer doesn't need the script any more, but streaming might |
251 // still be ongoing. Tell SourceStream to try to cancel it whenever it gets | 251 // still be ongoing. Tell SourceStream to try to cancel it whenever it gets |
252 // the control the next time. It can also be that V8 has already completed | 252 // the control the next time. It can also be that V8 has already completed |
253 // its operations and streamingComplete will be called soon. | 253 // its operations and streamingComplete will be called soon. |
254 m_detached = true; | 254 m_detached = true; |
255 m_resource = 0; | 255 m_resource = 0; |
256 m_stream->cancel(); | 256 if (m_stream) |
257 m_stream->cancel(); | |
257 } | 258 } |
258 | 259 |
259 void ScriptStreamer::suppressStreaming() | 260 void ScriptStreamer::suppressStreaming() |
260 { | 261 { |
261 MutexLocker locker(m_mutex); | 262 MutexLocker locker(m_mutex); |
262 ASSERT(!m_loadingFinished); | 263 ASSERT(!m_loadingFinished); |
263 // It can be that the parsing task has already finished (e.g., if there was | 264 // It can be that the parsing task has already finished (e.g., if there was |
264 // a parse error). | 265 // a parse error). |
265 m_streamingSuppressed = true; | 266 m_streamingSuppressed = true; |
266 } | 267 } |
267 | 268 |
269 unsigned ScriptStreamer::cachedDataType() const | |
270 { | |
271 if (m_compileOptions == v8::ScriptCompiler::kProduceParserCache) { | |
272 return V8ScriptRunner::tagForParserCache(); | |
273 } | |
274 if (m_compileOptions == v8::ScriptCompiler::kProduceCodeCache) { | |
275 return V8ScriptRunner::tagForCodeCache(); | |
276 } | |
277 return 0; | |
278 } | |
279 | |
268 void ScriptStreamer::notifyAppendData(ScriptResource* resource) | 280 void ScriptStreamer::notifyAppendData(ScriptResource* resource) |
269 { | 281 { |
270 ASSERT(isMainThread()); | 282 ASSERT(isMainThread()); |
271 ASSERT(m_resource == resource); | 283 ASSERT(m_resource == resource); |
272 { | 284 { |
273 MutexLocker locker(m_mutex); | 285 MutexLocker locker(m_mutex); |
274 if (m_streamingSuppressed) | 286 if (m_streamingSuppressed) |
275 return; | 287 return; |
276 } | 288 } |
277 if (!m_haveEnoughDataForStreaming) { | 289 if (!m_haveEnoughDataForStreaming) { |
278 // Even if the first data chunk is small, the script can still be big | 290 // Even if the first data chunk is small, the script can still be big |
279 // enough - wait until the next data chunk comes before deciding whether | 291 // enough - wait until the next data chunk comes before deciding whether |
280 // to start the streaming. | 292 // to start the streaming. |
281 if (resource->resourceBuffer()->size() < kSmallScriptThreshold) { | 293 if (resource->resourceBuffer()->size() < kSmallScriptThreshold) { |
282 return; | 294 return; |
283 } | 295 } |
284 m_haveEnoughDataForStreaming = true; | 296 m_haveEnoughDataForStreaming = true; |
285 const char* histogramName = startedStreamingHistogramName(m_scriptType); | 297 const char* histogramName = startedStreamingHistogramName(m_scriptType); |
298 | |
299 // Encoding should be detected only when we have some data. It's | |
300 // possible that resource->encoding() returns a different encoding | |
301 // before the loading has started and after we got some data. | |
302 WTF::TextEncoding textEncoding(resource->encoding()); | |
303 const char* encodingName = textEncoding.name(); | |
304 | |
305 // Here's a list of encodings we can use for streaming. These are | |
306 // the canonical names. | |
307 v8::ScriptCompiler::StreamedSource::Encoding encoding; | |
308 if (strcmp(encodingName, "windows-1252") == 0 | |
309 || strcmp(encodingName, "ISO-8859-1") == 0 | |
310 || strcmp(encodingName, "US-ASCII") == 0) { | |
haraken
2014/11/04 03:07:34
Can we share this code with ScriptStreamer::startS
marja
2014/11/04 09:15:53
Oops, my intention was to move the code here, so,
| |
311 encoding = v8::ScriptCompiler::StreamedSource::ONE_BYTE; | |
312 } else if (strcmp(encodingName, "UTF-8") == 0) { | |
313 encoding = v8::ScriptCompiler::StreamedSource::UTF8; | |
314 } else { | |
315 // We don't stream other encodings; especially we don't stream two | |
316 // byte scripts to avoid the handling of byte order marks. Most | |
317 // scripts are Latin1 or UTF-8 anyway, so this should be enough for | |
318 // most real world purposes. | |
319 suppressStreaming(); | |
320 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2 ); | |
321 return; | |
322 } | |
286 if (ScriptStreamerThread::shared()->isRunningTask()) { | 323 if (ScriptStreamerThread::shared()->isRunningTask()) { |
287 // At the moment we only have one thread for running the tasks. A | 324 // At the moment we only have one thread for running the tasks. A |
288 // new task shouldn't be queued before the running task completes, | 325 // new task shouldn't be queued before the running task completes, |
289 // because the running task can block and wait for data from the | 326 // because the running task can block and wait for data from the |
290 // network. | 327 // network. |
291 suppressStreaming(); | 328 suppressStreaming(); |
292 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2 ); | 329 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2 ); |
293 return; | 330 return; |
294 } | 331 } |
295 ASSERT(m_task); | 332 |
333 ASSERT(!m_stream); | |
334 ASSERT(!m_source); | |
335 m_stream = new SourceStream(this); | |
336 // m_source takes ownership of m_stream. | |
337 m_source = adoptPtr(new v8::ScriptCompiler::StreamedSource(m_stream, enc oding)); | |
338 | |
339 ScriptState::Scope scope(m_scriptState); | |
haraken
2014/11/04 03:07:33
Why do you need to enter a ScriptState ?
marja
2014/11/04 09:15:53
Because V8 wants to check the current context (to
| |
340 WTF::OwnPtr<v8::ScriptCompiler::ScriptStreamingTask> scriptStreamingTask (adoptPtr(v8::ScriptCompiler::StartStreamingScript(m_scriptState->isolate(), m_s ource.get(), m_compileOptions))); | |
341 if (!scriptStreamingTask) { | |
342 // V8 cannot stream the script. | |
343 suppressStreaming(); | |
344 m_stream = 0; | |
345 m_source.clear(); | |
346 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2 ); | |
347 return; | |
348 } | |
349 | |
296 // ScriptStreamer needs to stay alive as long as the background task is | 350 // ScriptStreamer needs to stay alive as long as the background task is |
297 // running. This is taken care of with a manual ref() & deref() pair; | 351 // running. This is taken care of with a manual ref() & deref() pair; |
298 // the corresponding deref() is in streamingComplete or in | 352 // the corresponding deref() is in streamingComplete or in |
299 // notifyFinished. | 353 // notifyFinished. |
300 ref(); | 354 ref(); |
301 ScriptStreamingTask* task = new ScriptStreamingTask(m_task.release(), th is); | 355 ScriptStreamingTask* task = new ScriptStreamingTask(scriptStreamingTask. release(), this); |
302 ScriptStreamerThread::shared()->postTask(task); | 356 ScriptStreamerThread::shared()->postTask(task); |
303 blink::Platform::current()->histogramEnumeration(histogramName, 1, 2); | 357 blink::Platform::current()->histogramEnumeration(histogramName, 1, 2); |
304 } | 358 } |
305 m_stream->didReceiveData(); | 359 if (m_stream) |
360 m_stream->didReceiveData(); | |
306 } | 361 } |
307 | 362 |
308 void ScriptStreamer::notifyFinished(Resource* resource) | 363 void ScriptStreamer::notifyFinished(Resource* resource) |
309 { | 364 { |
310 ASSERT(isMainThread()); | 365 ASSERT(isMainThread()); |
311 ASSERT(m_resource == resource); | 366 ASSERT(m_resource == resource); |
312 // A special case: empty and small scripts. We didn't receive enough data to | 367 // A special case: empty and small scripts. We didn't receive enough data to |
313 // start the streaming before this notification. In that case, there won't | 368 // start the streaming before this notification. In that case, there won't |
314 // be a "parsing complete" notification either, and we should not wait for | 369 // be a "parsing complete" notification either, and we should not wait for |
315 // it. | 370 // it. |
316 if (!m_haveEnoughDataForStreaming) { | 371 if (!m_haveEnoughDataForStreaming) { |
317 const char* histogramName = startedStreamingHistogramName(m_scriptType); | 372 const char* histogramName = startedStreamingHistogramName(m_scriptType); |
318 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2); | 373 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2); |
319 suppressStreaming(); | 374 suppressStreaming(); |
320 } | 375 } |
321 m_stream->didFinishLoading(); | 376 if (m_stream) |
377 m_stream->didFinishLoading(); | |
322 m_loadingFinished = true; | 378 m_loadingFinished = true; |
323 | 379 |
324 if (shouldBlockMainThread()) { | 380 if (shouldBlockMainThread()) { |
325 // Make the main thead wait until the streaming is complete, to make | 381 // Make the main thead wait until the streaming is complete, to make |
326 // sure that the script gets the main thread's attention as early as | 382 // sure that the script gets the main thread's attention as early as |
327 // possible (for possible compiling, if the client wants to do it | 383 // possible (for possible compiling, if the client wants to do it |
328 // right away). Note that blocking here is not any worse than the | 384 // right away). Note that blocking here is not any worse than the |
329 // non-streaming code path where the main thread eventually blocks | 385 // non-streaming code path where the main thread eventually blocks |
330 // to parse the script. | 386 // to parse the script. |
331 TRACE_EVENT0("v8", "v8.mainThreadWaitingForParserThread"); | 387 TRACE_EVENT0("v8", "v8.mainThreadWaitingForParserThread"); |
(...skipping 14 matching lines...) Expand all Loading... | |
346 | 402 |
347 if (m_mainThreadWaitingForParserThread) { | 403 if (m_mainThreadWaitingForParserThread) { |
348 ASSERT(m_parsingFinished); | 404 ASSERT(m_parsingFinished); |
349 ASSERT(!m_streamingSuppressed); | 405 ASSERT(!m_streamingSuppressed); |
350 // streamingComplete won't be called, so do the ramp-down work | 406 // streamingComplete won't be called, so do the ramp-down work |
351 // here. | 407 // here. |
352 deref(); | 408 deref(); |
353 } | 409 } |
354 } | 410 } |
355 | 411 |
356 ScriptStreamer::ScriptStreamer(ScriptResource* resource, v8::ScriptCompiler::Str eamedSource::Encoding encoding, PendingScript::Type scriptType, ScriptStreamingM ode mode) | 412 ScriptStreamer::ScriptStreamer(ScriptResource* resource, PendingScript::Type scr iptType, ScriptStreamingMode mode, ScriptState* scriptState, v8::ScriptCompiler: :CompileOptions compileOptions) |
357 : m_resource(resource) | 413 : m_resource(resource) |
358 , m_detached(false) | 414 , m_detached(false) |
359 , m_stream(new SourceStream(this)) | 415 , m_stream(0) |
360 , m_source(m_stream, encoding) // m_source takes ownership of m_stream. | |
361 , m_client(0) | 416 , m_client(0) |
362 , m_loadingFinished(false) | 417 , m_loadingFinished(false) |
363 , m_parsingFinished(false) | 418 , m_parsingFinished(false) |
364 , m_haveEnoughDataForStreaming(false) | 419 , m_haveEnoughDataForStreaming(false) |
365 , m_streamingSuppressed(false) | 420 , m_streamingSuppressed(false) |
421 , m_compileOptions(compileOptions) | |
422 , m_scriptState(scriptState) | |
366 , m_scriptType(scriptType) | 423 , m_scriptType(scriptType) |
367 , m_scriptStreamingMode(mode) | 424 , m_scriptStreamingMode(mode) |
368 , m_mainThreadWaitingForParserThread(false) | 425 , m_mainThreadWaitingForParserThread(false) |
369 { | 426 { |
370 } | 427 } |
371 | 428 |
372 void ScriptStreamer::streamingComplete() | 429 void ScriptStreamer::streamingComplete() |
373 { | 430 { |
374 // The background task is completed; do the necessary ramp-down in the main | 431 // The background task is completed; do the necessary ramp-down in the main |
375 // thread. | 432 // thread. |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
471 } else { | 528 } else { |
472 // We don't stream other encodings; especially we don't stream two byte | 529 // We don't stream other encodings; especially we don't stream two byte |
473 // scripts to avoid the handling of byte order marks. Most scripts are | 530 // scripts to avoid the handling of byte order marks. Most scripts are |
474 // Latin1 or UTF-8 anyway, so this should be enough for most real world | 531 // Latin1 or UTF-8 anyway, so this should be enough for most real world |
475 // purposes. | 532 // purposes. |
476 return false; | 533 return false; |
477 } | 534 } |
478 | 535 |
479 if (!scriptState->contextIsValid()) | 536 if (!scriptState->contextIsValid()) |
480 return false; | 537 return false; |
481 ScriptState::Scope scope(scriptState); | |
482 | |
483 // The Resource might go out of scope if the script is no longer needed. We | |
484 // will soon call PendingScript::setStreamer, which makes the PendingScript | |
485 // notify the ScriptStreamer when it is destroyed. | |
486 RefPtr<ScriptStreamer> streamer = adoptRef(new ScriptStreamer(resource, enco ding, scriptType, settings->v8ScriptStreamingMode())); | |
487 | 538 |
488 // Decide what kind of cached data we should produce while streaming. By | 539 // Decide what kind of cached data we should produce while streaming. By |
489 // default, we generate the parser cache for streamed scripts, to emulate | 540 // default, we generate the parser cache for streamed scripts, to emulate |
490 // the non-streaming behavior (see V8ScriptRunner::compileScript). | 541 // the non-streaming behavior (see V8ScriptRunner::compileScript). |
491 v8::ScriptCompiler::CompileOptions compileOption = v8::ScriptCompiler::kProd uceParserCache; | 542 v8::ScriptCompiler::CompileOptions compileOption = v8::ScriptCompiler::kProd uceParserCache; |
492 if (settings->v8CacheOptions() == V8CacheOptionsCode) | 543 if (settings->v8CacheOptions() == V8CacheOptionsCode) |
493 compileOption = v8::ScriptCompiler::kProduceCodeCache; | 544 compileOption = v8::ScriptCompiler::kProduceCodeCache; |
494 v8::ScriptCompiler::ScriptStreamingTask* scriptStreamingTask = v8::ScriptCom piler::StartStreamingScript(scriptState->isolate(), &(streamer->m_source), compi leOption); | 545 |
495 if (scriptStreamingTask) { | 546 // The Resource might go out of scope if the script is no longer |
496 streamer->m_task = adoptPtr(scriptStreamingTask); | 547 // needed. This makes PendingScript notify the ScriptStreamer when it is |
497 script.setStreamer(streamer.release()); | 548 // destroyed. |
498 return true; | 549 script.setStreamer(adoptRef(new ScriptStreamer(resource, scriptType, setting s->v8ScriptStreamingMode(), scriptState, compileOption))); |
499 } | 550 |
500 // Otherwise, V8 cannot stream the script. | 551 return true; |
501 return false; | |
502 } | 552 } |
503 | 553 |
504 } // namespace blink | 554 } // namespace blink |
OLD | NEW |