OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. | 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 13 matching lines...) Expand all Loading... |
24 */ | 24 */ |
25 | 25 |
26 #include "core/html/parser/HTMLParserScriptRunner.h" | 26 #include "core/html/parser/HTMLParserScriptRunner.h" |
27 | 27 |
28 #include <inttypes.h> | 28 #include <inttypes.h> |
29 #include <memory> | 29 #include <memory> |
30 #include "bindings/core/v8/Microtask.h" | 30 #include "bindings/core/v8/Microtask.h" |
31 #include "bindings/core/v8/ScriptSourceCode.h" | 31 #include "bindings/core/v8/ScriptSourceCode.h" |
32 #include "bindings/core/v8/V8Binding.h" | 32 #include "bindings/core/v8/V8Binding.h" |
33 #include "bindings/core/v8/V8PerIsolateData.h" | 33 #include "bindings/core/v8/V8PerIsolateData.h" |
| 34 #include "core/dom/ClassicPendingScript.h" |
34 #include "core/dom/ClassicScript.h" | 35 #include "core/dom/ClassicScript.h" |
35 #include "core/dom/DocumentParserTiming.h" | 36 #include "core/dom/DocumentParserTiming.h" |
36 #include "core/dom/Element.h" | 37 #include "core/dom/Element.h" |
37 #include "core/dom/IgnoreDestructiveWriteCountIncrementer.h" | 38 #include "core/dom/IgnoreDestructiveWriteCountIncrementer.h" |
38 #include "core/dom/ScriptLoader.h" | 39 #include "core/dom/ScriptLoader.h" |
39 #include "core/dom/TaskRunnerHelper.h" | 40 #include "core/dom/TaskRunnerHelper.h" |
40 #include "core/events/Event.h" | 41 #include "core/events/Event.h" |
41 #include "core/frame/LocalFrame.h" | 42 #include "core/frame/LocalFrame.h" |
42 #include "core/html/parser/HTMLInputStream.h" | 43 #include "core/html/parser/HTMLInputStream.h" |
43 #include "core/html/parser/HTMLParserScriptRunnerHost.h" | 44 #include "core/html/parser/HTMLParserScriptRunnerHost.h" |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 if (parserBlockingScript() != pendingScript) | 329 if (parserBlockingScript() != pendingScript) |
329 return; | 330 return; |
330 | 331 |
331 ScriptElementBase* element = parserBlockingScript()->element(); | 332 ScriptElementBase* element = parserBlockingScript()->element(); |
332 | 333 |
333 ScriptLoader* scriptLoader = element->loader(); | 334 ScriptLoader* scriptLoader = element->loader(); |
334 if (!scriptLoader || !scriptLoader->disallowedFetchForDocWrittenScript()) | 335 if (!scriptLoader || !scriptLoader->disallowedFetchForDocWrittenScript()) |
335 return; | 336 return; |
336 | 337 |
337 if (!pendingScript->errorOccurred()) { | 338 if (!pendingScript->errorOccurred()) { |
338 emitWarningForDocWriteScripts(pendingScript->resource()->url().getString(), | 339 emitWarningForDocWriteScripts(pendingScript->url().getString(), |
339 *m_document); | 340 *m_document); |
340 return; | 341 return; |
341 } | 342 } |
342 | 343 |
343 // Due to dependency violation, not able to check the exact error to be | 344 // Due to dependency violation, not able to check the exact error to be |
344 // ERR_CACHE_MISS but other errors are rare with | 345 // ERR_CACHE_MISS but other errors are rare with |
345 // WebCachePolicy::ReturnCacheDataDontLoad. | 346 // WebCachePolicy::ReturnCacheDataDontLoad. |
346 | 347 |
347 emitErrorForDocWriteScripts(pendingScript->resource()->url().getString(), | 348 emitErrorForDocWriteScripts(pendingScript->url().getString(), *m_document); |
348 *m_document); | |
349 TextPosition startingPosition = parserBlockingScript()->startingPosition(); | 349 TextPosition startingPosition = parserBlockingScript()->startingPosition(); |
350 bool isParserInserted = scriptLoader->isParserInserted(); | 350 bool isParserInserted = scriptLoader->isParserInserted(); |
351 // Remove this resource entry from memory cache as the new request | 351 // Remove this resource entry from memory cache as the new request |
352 // should not join onto this existing entry. | 352 // should not join onto this existing entry. |
353 memoryCache()->remove(pendingScript->resource()); | 353 // memoryCache()->remove(pendingScript->resource()); |
354 fetchBlockedDocWriteScript(element, isParserInserted, startingPosition); | 354 fetchBlockedDocWriteScript(element, isParserInserted, startingPosition); |
355 } | 355 } |
356 | 356 |
357 void HTMLParserScriptRunner::pendingScriptFinished( | 357 void HTMLParserScriptRunner::pendingScriptFinished( |
358 PendingScript* pendingScript) { | 358 PendingScript* pendingScript) { |
359 // Handle cancellations of parser-blocking script loads without | 359 // Handle cancellations of parser-blocking script loads without |
360 // notifying the host (i.e., parser) if these were initiated by nested | 360 // notifying the host (i.e., parser) if these were initiated by nested |
361 // document.write()s. The cancellation may have been triggered by | 361 // document.write()s. The cancellation may have been triggered by |
362 // script execution to signal an abrupt stop (e.g., window.close().) | 362 // script execution to signal an abrupt stop (e.g., window.close().) |
363 // | 363 // |
364 // The parser is unprepared to be told, and doesn't need to be. | 364 // The parser is unprepared to be told, and doesn't need to be. |
365 if (isExecutingScript() && pendingScript->resource()->wasCanceled()) { | 365 if (isExecutingScript() && pendingScript->wasCanceled()) { |
366 pendingScript->dispose(); | 366 pendingScript->dispose(); |
367 | 367 |
368 if (pendingScript == parserBlockingScript()) { | 368 if (pendingScript == parserBlockingScript()) { |
369 m_parserBlockingScript = nullptr; | 369 m_parserBlockingScript = nullptr; |
370 } else { | 370 } else { |
371 CHECK_EQ(pendingScript, m_scriptsToExecuteAfterParsing.front()); | 371 CHECK_EQ(pendingScript, m_scriptsToExecuteAfterParsing.front()); |
372 | 372 |
373 // TODO(hiroshige): Remove this CHECK() before going to beta. | 373 // TODO(hiroshige): Remove this CHECK() before going to beta. |
374 // This is only to make clusterfuzz to find a test case that executes | 374 // This is only to make clusterfuzz to find a test case that executes |
375 // this code path. | 375 // this code path. |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 // Step 3 of https://html.spec.whatwg.org/#the-end: | 497 // Step 3 of https://html.spec.whatwg.org/#the-end: |
498 // "If the list of scripts that will execute when the document has | 498 // "If the list of scripts that will execute when the document has |
499 // finished parsing is not empty, run these substeps:" | 499 // finished parsing is not empty, run these substeps:" |
500 bool HTMLParserScriptRunner::executeScriptsWaitingForParsing() { | 500 bool HTMLParserScriptRunner::executeScriptsWaitingForParsing() { |
501 TRACE_EVENT0("blink", | 501 TRACE_EVENT0("blink", |
502 "HTMLParserScriptRunner::executeScriptsWaitingForParsing"); | 502 "HTMLParserScriptRunner::executeScriptsWaitingForParsing"); |
503 | 503 |
504 while (!m_scriptsToExecuteAfterParsing.isEmpty()) { | 504 while (!m_scriptsToExecuteAfterParsing.isEmpty()) { |
505 DCHECK(!isExecutingScript()); | 505 DCHECK(!isExecutingScript()); |
506 DCHECK(!hasParserBlockingScript()); | 506 DCHECK(!hasParserBlockingScript()); |
507 DCHECK(m_scriptsToExecuteAfterParsing.front()->resource()); | 507 DCHECK(m_scriptsToExecuteAfterParsing.front()->isExternal()); |
508 | 508 |
509 // 1. "Spin the event loop until the first script in the list of scripts | 509 // 1. "Spin the event loop until the first script in the list of scripts |
510 // that will execute when the document has finished parsing | 510 // that will execute when the document has finished parsing |
511 // has its "ready to be parser-executed" flag set and | 511 // has its "ready to be parser-executed" flag set and |
512 // the parser's Document has no style sheet that is blocking scripts." | 512 // the parser's Document has no style sheet that is blocking scripts." |
513 // TODO(hiroshige): Is the latter part checked anywhere? | 513 // TODO(hiroshige): Is the latter part checked anywhere? |
514 if (!m_scriptsToExecuteAfterParsing.front()->isReady()) { | 514 if (!m_scriptsToExecuteAfterParsing.front()->isReady()) { |
515 m_scriptsToExecuteAfterParsing.front()->watchForLoad(this); | 515 m_scriptsToExecuteAfterParsing.front()->watchForLoad(this); |
516 traceParserBlockingScript(m_scriptsToExecuteAfterParsing.front().get(), | 516 traceParserBlockingScript(m_scriptsToExecuteAfterParsing.front().get(), |
517 !m_document->isScriptExecutionReady()); | 517 !m_document->isScriptExecutionReady()); |
(...skipping 24 matching lines...) Expand all Loading... |
542 // 2nd Clause, Step 23 of https://html.spec.whatwg.org/#prepare-a-script | 542 // 2nd Clause, Step 23 of https://html.spec.whatwg.org/#prepare-a-script |
543 void HTMLParserScriptRunner::requestParsingBlockingScript(Element* element) { | 543 void HTMLParserScriptRunner::requestParsingBlockingScript(Element* element) { |
544 // "The element is the pending parsing-blocking script of the Document of | 544 // "The element is the pending parsing-blocking script of the Document of |
545 // the parser that created the element. | 545 // the parser that created the element. |
546 // (There can only be one such script per Document at a time.)" | 546 // (There can only be one such script per Document at a time.)" |
547 CHECK(!parserBlockingScript()); | 547 CHECK(!parserBlockingScript()); |
548 m_parserBlockingScript = requestPendingScript(element); | 548 m_parserBlockingScript = requestPendingScript(element); |
549 if (!parserBlockingScript()) | 549 if (!parserBlockingScript()) |
550 return; | 550 return; |
551 | 551 |
552 DCHECK(parserBlockingScript()->resource()); | |
553 | |
554 // We only care about a load callback if resource is not already in the cache. | 552 // We only care about a load callback if resource is not already in the cache. |
555 // Callers will attempt to run the m_parserBlockingScript if possible before | 553 // Callers will attempt to run the m_parserBlockingScript if possible before |
556 // returning control to the parser. | 554 // returning control to the parser. |
557 if (!parserBlockingScript()->isReady()) { | 555 if (!parserBlockingScript()->isReady()) { |
558 m_parserBlockingScript->startStreamingIfPossible( | 556 m_parserBlockingScript->startStreamingIfPossible( |
559 m_document, ScriptStreamer::ParsingBlocking); | 557 m_document, ScriptStreamer::ParsingBlocking); |
560 m_parserBlockingScript->watchForLoad(this); | 558 m_parserBlockingScript->watchForLoad(this); |
561 } | 559 } |
562 } | 560 } |
563 | 561 |
564 // 1st Clause, Step 23 of https://html.spec.whatwg.org/#prepare-a-script | 562 // 1st Clause, Step 23 of https://html.spec.whatwg.org/#prepare-a-script |
565 void HTMLParserScriptRunner::requestDeferredScript(Element* element) { | 563 void HTMLParserScriptRunner::requestDeferredScript(Element* element) { |
566 PendingScript* pendingScript = requestPendingScript(element); | 564 PendingScript* pendingScript = requestPendingScript(element); |
567 if (!pendingScript) | 565 if (!pendingScript) |
568 return; | 566 return; |
569 | 567 |
570 if (!pendingScript->isReady()) { | 568 if (!pendingScript->isReady()) { |
571 pendingScript->startStreamingIfPossible(m_document, | 569 pendingScript->startStreamingIfPossible(m_document, |
572 ScriptStreamer::Deferred); | 570 ScriptStreamer::Deferred); |
573 } | 571 } |
574 | 572 |
575 DCHECK(pendingScript->resource()); | |
576 | |
577 // "Add the element to the end of the list of scripts that will execute | 573 // "Add the element to the end of the list of scripts that will execute |
578 // when the document has finished parsing associated with the Document | 574 // when the document has finished parsing associated with the Document |
579 // of the parser that created the element." | 575 // of the parser that created the element." |
580 m_scriptsToExecuteAfterParsing.push_back(pendingScript); | 576 m_scriptsToExecuteAfterParsing.push_back(pendingScript); |
581 } | 577 } |
582 | 578 |
583 PendingScript* HTMLParserScriptRunner::requestPendingScript( | 579 PendingScript* HTMLParserScriptRunner::requestPendingScript( |
584 Element* element) const { | 580 Element* element) const { |
585 ScriptElementBase* scriptElement = | 581 ScriptElementBase* scriptElement = |
586 ScriptElementBase::fromElementIfPossible(element); | 582 ScriptElementBase::fromElementIfPossible(element); |
587 ScriptResource* resource = scriptElement->loader()->resource(); | 583 ScriptResource* resource = scriptElement->loader()->resource(); |
588 // Here |resource| should be non-null. If it were nullptr, | 584 // Here |resource| should be non-null. If it were nullptr, |
589 // ScriptLoader::fetchScript() should have returned false and | 585 // ScriptLoader::fetchScript() should have returned false and |
590 // thus the control shouldn't have reached here. | 586 // thus the control shouldn't have reached here. |
591 CHECK(resource); | 587 CHECK(resource); |
592 return PendingScript::create(scriptElement, resource); | 588 ClassicPendingScript* pendingScript = |
| 589 ClassicPendingScript::create(scriptElement, resource); |
| 590 DCHECK(pendingScript->resource()); |
| 591 return pendingScript; |
593 } | 592 } |
594 | 593 |
595 // The initial steps for 'An end tag whose tag name is "script"' | 594 // The initial steps for 'An end tag whose tag name is "script"' |
596 // https://html.spec.whatwg.org/#scriptEndTag | 595 // https://html.spec.whatwg.org/#scriptEndTag |
597 void HTMLParserScriptRunner::processScriptElementInternal( | 596 void HTMLParserScriptRunner::processScriptElementInternal( |
598 Element* script, | 597 Element* script, |
599 const TextPosition& scriptStartPosition) { | 598 const TextPosition& scriptStartPosition) { |
600 DCHECK(m_document); | 599 DCHECK(m_document); |
601 DCHECK(!hasParserBlockingScript()); | 600 DCHECK(!hasParserBlockingScript()); |
602 { | 601 { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 } else if (scriptLoader->readyToBeParserExecuted()) { | 639 } else if (scriptLoader->readyToBeParserExecuted()) { |
641 // 5th Clause of Step 23. | 640 // 5th Clause of Step 23. |
642 // "If ... it's an HTML parser | 641 // "If ... it's an HTML parser |
643 // whose script nesting level is not greater than one" | 642 // whose script nesting level is not greater than one" |
644 if (m_reentryPermit->scriptNestingLevel() == 1u) { | 643 if (m_reentryPermit->scriptNestingLevel() == 1u) { |
645 // "The element is the pending parsing-blocking script of the | 644 // "The element is the pending parsing-blocking script of the |
646 // Document of the parser that created the element. | 645 // Document of the parser that created the element. |
647 // (There can only be one such script per Document at a time.)" | 646 // (There can only be one such script per Document at a time.)" |
648 CHECK(!m_parserBlockingScript); | 647 CHECK(!m_parserBlockingScript); |
649 m_parserBlockingScript = | 648 m_parserBlockingScript = |
650 PendingScript::create(element, scriptStartPosition); | 649 ClassicPendingScript::create(element, scriptStartPosition); |
651 } else { | 650 } else { |
652 // 6th Clause of Step 23. | 651 // 6th Clause of Step 23. |
653 // "Immediately execute the script block, | 652 // "Immediately execute the script block, |
654 // even if other scripts are already executing." | 653 // even if other scripts are already executing." |
655 // TODO(hiroshige): Merge the block into ScriptLoader::prepareScript(). | 654 // TODO(hiroshige): Merge the block into ScriptLoader::prepareScript(). |
656 DCHECK_GT(m_reentryPermit->scriptNestingLevel(), 1u); | 655 DCHECK_GT(m_reentryPermit->scriptNestingLevel(), 1u); |
657 if (m_parserBlockingScript) | 656 if (m_parserBlockingScript) |
658 m_parserBlockingScript->dispose(); | 657 m_parserBlockingScript->dispose(); |
659 m_parserBlockingScript = nullptr; | 658 m_parserBlockingScript = nullptr; |
660 ScriptSourceCode sourceCode(script->textContent(), | 659 ScriptSourceCode sourceCode(script->textContent(), |
(...skipping 19 matching lines...) Expand all Loading... |
680 | 679 |
681 DEFINE_TRACE(HTMLParserScriptRunner) { | 680 DEFINE_TRACE(HTMLParserScriptRunner) { |
682 visitor->trace(m_document); | 681 visitor->trace(m_document); |
683 visitor->trace(m_host); | 682 visitor->trace(m_host); |
684 visitor->trace(m_parserBlockingScript); | 683 visitor->trace(m_parserBlockingScript); |
685 visitor->trace(m_scriptsToExecuteAfterParsing); | 684 visitor->trace(m_scriptsToExecuteAfterParsing); |
686 PendingScriptClient::trace(visitor); | 685 PendingScriptClient::trace(visitor); |
687 } | 686 } |
688 | 687 |
689 } // namespace blink | 688 } // namespace blink |
OLD | NEW |