| 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 |