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

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

Issue 700543002: Script streaming: detect encoding later. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Code review (haraken@) Created 6 years, 1 month 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"
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
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) {
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.get());
haraken 2014/11/04 10:36:38 I guess you need to check: if (!m_scriptState->
marja 2014/11/04 10:41:39 Ok; this is already checked in startStreamingInter
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
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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 if (resource->resourceToRevalidate()) { 506 if (resource->resourceToRevalidate()) {
450 // This happens e.g., during reloads. We're actually not going to load 507 // This happens e.g., during reloads. We're actually not going to load
451 // the current Resource of the PendingScript but switch to another 508 // the current Resource of the PendingScript but switch to another
452 // Resource -> don't stream. 509 // Resource -> don't stream.
453 return false; 510 return false;
454 } 511 }
455 // We cannot filter out short scripts, even if we wait for the HTTP headers 512 // We cannot filter out short scripts, even if we wait for the HTTP headers
456 // to arrive. In general, the web servers don't seem to send the 513 // to arrive. In general, the web servers don't seem to send the
457 // Content-Length HTTP header for scripts. 514 // Content-Length HTTP header for scripts.
458 515
459 WTF::TextEncoding textEncoding(resource->encoding());
460 const char* encodingName = textEncoding.name();
461
462 // Here's a list of encodings we can use for streaming. These are
463 // the canonical names.
464 v8::ScriptCompiler::StreamedSource::Encoding encoding;
465 if (strcmp(encodingName, "windows-1252") == 0
466 || strcmp(encodingName, "ISO-8859-1") == 0
467 || strcmp(encodingName, "US-ASCII") == 0) {
468 encoding = v8::ScriptCompiler::StreamedSource::ONE_BYTE;
469 } else if (strcmp(encodingName, "UTF-8") == 0) {
470 encoding = v8::ScriptCompiler::StreamedSource::UTF8;
471 } else {
472 // 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
474 // Latin1 or UTF-8 anyway, so this should be enough for most real world
475 // purposes.
476 return false;
477 }
478
479 if (!scriptState->contextIsValid()) 516 if (!scriptState->contextIsValid())
480 return false; 517 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 518
488 // Decide what kind of cached data we should produce while streaming. By 519 // Decide what kind of cached data we should produce while streaming. By
489 // default, we generate the parser cache for streamed scripts, to emulate 520 // default, we generate the parser cache for streamed scripts, to emulate
490 // the non-streaming behavior (see V8ScriptRunner::compileScript). 521 // the non-streaming behavior (see V8ScriptRunner::compileScript).
491 v8::ScriptCompiler::CompileOptions compileOption = v8::ScriptCompiler::kProd uceParserCache; 522 v8::ScriptCompiler::CompileOptions compileOption = v8::ScriptCompiler::kProd uceParserCache;
492 if (settings->v8CacheOptions() == V8CacheOptionsCode) 523 if (settings->v8CacheOptions() == V8CacheOptionsCode)
493 compileOption = v8::ScriptCompiler::kProduceCodeCache; 524 compileOption = v8::ScriptCompiler::kProduceCodeCache;
494 v8::ScriptCompiler::ScriptStreamingTask* scriptStreamingTask = v8::ScriptCom piler::StartStreamingScript(scriptState->isolate(), &(streamer->m_source), compi leOption); 525
495 if (scriptStreamingTask) { 526 // The Resource might go out of scope if the script is no longer
496 streamer->m_task = adoptPtr(scriptStreamingTask); 527 // needed. This makes PendingScript notify the ScriptStreamer when it is
497 script.setStreamer(streamer.release()); 528 // destroyed.
498 return true; 529 script.setStreamer(adoptRef(new ScriptStreamer(resource, scriptType, setting s->v8ScriptStreamingMode(), scriptState, compileOption)));
499 } 530
500 // Otherwise, V8 cannot stream the script. 531 return true;
501 return false;
502 } 532 }
503 533
504 } // namespace blink 534 } // 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