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

Unified Diff: third_party/WebKit/Source/core/dom/ScriptLoader.cpp

Issue 2541613002: DO NOT SUBMIT: Sketching out ScriptLoader::executeScriptAsync.
Patch Set: . Created 4 years 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/dom/ScriptLoader.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/core/dom/ScriptLoader.cpp
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
index a02e2ca2086a275cb4d1cf3ef5647e11e0236ce3..400c7167c3dabdd04366eb0519e13fb6ac939064 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -24,6 +24,7 @@
#include "core/dom/ScriptLoader.h"
+#include "bindings/core/v8/CompiledScript.h"
#include "bindings/core/v8/ScriptController.h"
#include "bindings/core/v8/ScriptSourceCode.h"
#include "core/HTMLNames.h"
@@ -34,6 +35,7 @@
#include "core/dom/ScriptLoaderClient.h"
#include "core/dom/ScriptRunner.h"
#include "core/dom/ScriptableDocumentParser.h"
+#include "core/dom/TaskRunnerHelper.h"
#include "core/dom/Text.h"
#include "core/events/Event.h"
#include "core/fetch/AccessControlStatus.h"
@@ -53,6 +55,7 @@
#include "platform/WebFrameScheduler.h"
#include "platform/network/mime/MIMETypeRegistry.h"
#include "platform/weborigin/SecurityOrigin.h"
+#include "public/platform/Platform.h"
#include "public/platform/WebCachePolicy.h"
#include "wtf/StdLibExtras.h"
#include "wtf/text/StringBuilder.h"
@@ -430,32 +433,107 @@ void ScriptLoader::logScriptMIMEType(LocalFrame* frame,
bool ScriptLoader::executeScript(const ScriptSourceCode& sourceCode) {
double scriptExecStartTime = monotonicallyIncreasingTime();
- bool result = doExecuteScript(sourceCode);
- // NOTE: we do not check m_willBeParserExecuted here, since
- // m_willBeParserExecuted is false for inline scripts, and we want to
- // include inline script execution time as part of parser blocked script
- // execution time.
- if (m_asyncExecType == ScriptRunner::None)
- DocumentParserTiming::from(m_element->document())
- .recordParserBlockedOnScriptExecutionDuration(
- monotonicallyIncreasingTime() - scriptExecStartTime,
- wasCreatedDuringDocumentWrite());
- return result;
+ CheckScriptResult result = checkScript(sourceCode);
+ if (result == CheckScriptResult::Proceed) {
+ AccessControlStatus accessControlStatus =
+ computeAccessControlStatus(sourceCode);
+ asCurrentScript(
+ [&sourceCode, accessControlStatus](ScriptController& scriptController) {
+ scriptController.executeScriptInMainWorld(sourceCode,
+ accessControlStatus);
+ });
+ }
+
+ recordParserBlockedOnScriptExecutionSince(scriptExecStartTime);
+ return result != CheckScriptResult::Abort;
+}
+
+void ScriptLoader::executeScriptAsync(
+ const ScriptSourceCode& sourceCode,
+ std::unique_ptr<ExecuteScriptAsyncCallback> completionCallback) {
+ DCHECK(completionCallback);
+ double scriptCompileStartTime = monotonicallyIncreasingTime();
+
+ AccessControlStatus accessControlStatus =
+ computeAccessControlStatus(sourceCode);
+ Document* elementDocument = &(m_element->document());
+ Document* contextDocument = elementDocument->contextDocument();
+ LocalFrame* frame = contextDocument->frame();
+
+ // TODO(jbroman): Could call checkScript here first.
+ // This would arguably be redundant, especially if we call it synchronously.
+ // On the other hand, it could also avoid compiling something that cannot
+ // execute.
+
+ CompiledScript* compiled =
+ frame->script().compileScriptInMainWorld(sourceCode, accessControlStatus);
+ recordParserBlockedOnScriptExecutionSince(scriptCompileStartTime);
+
+ if (!compiled) {
+ (*completionCallback)(true);
+ return;
+ }
+
+ static const unsigned kSmallScriptSize = 30 * 1024;
+ const bool shouldYield = sourceCode.source().length() >= kSmallScriptSize &&
+ Platform::current()
+ ->mainThread()
+ ->scheduler()
+ ->shouldYieldForHighPriorityWork();
+ if (shouldYield) {
+ std::unique_ptr<WTF::Closure> continuation = WTF::bind(
+ &ScriptLoader::continueExecuteScriptAsync, wrapPersistent(this),
+ wrapPersistent(compiled), wrapPersistent(elementDocument),
+ WTF::passed(std::move(completionCallback)));
+ TaskRunnerHelper::get(TaskType::Networking, frame)
+ ->postTask(BLINK_FROM_HERE, std::move(continuation));
+ } else {
+ continueExecuteScriptAsync(compiled, elementDocument,
+ std::move(completionCallback));
+ }
}
-bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) {
+void ScriptLoader::continueExecuteScriptAsync(
+ CompiledScript* compiled,
+ Document* elementDocumentWhenCompiled,
+ std::unique_ptr<ExecuteScriptAsyncCallback> completionCallback) {
+ double scriptExecStartTime = monotonicallyIncreasingTime();
+
+ CheckScriptResult result = checkScript(compiled->sourceCode());
+ if (result == CheckScriptResult::Proceed) {
+ asCurrentScript([this, compiled, elementDocumentWhenCompiled](
+ ScriptController& scriptController) {
+ if (m_element->document() == elementDocumentWhenCompiled) {
+ scriptController.executeScriptInMainWorld(*compiled);
+ } else {
+ // This will recompile the source code. But it only happens when the
+ // element moves to a new document at an inopportune time, which
+ // should be rare.
+ scriptController.executeScriptInMainWorld(compiled->sourceCode());
+ }
+ });
+ }
+
+ recordParserBlockedOnScriptExecutionSince(scriptExecStartTime);
+ (*completionCallback)(result != CheckScriptResult::Abort);
+}
+
+ScriptLoader::CheckScriptResult ScriptLoader::checkScript(
+ const ScriptSourceCode& sourceCode) {
DCHECK(m_alreadyStarted);
if (sourceCode.isEmpty())
- return true;
+ return CheckScriptResult::NothingToDo;
Document* elementDocument = &(m_element->document());
Document* contextDocument = elementDocument->contextDocument();
if (!contextDocument)
- return true;
+ return CheckScriptResult::NothingToDo;
LocalFrame* frame = contextDocument->frame();
+ if (!frame)
+ return CheckScriptResult::NothingToDo;
const ContentSecurityPolicy* csp = elementDocument->contentSecurityPolicy();
bool shouldBypassMainWorldCSP =
@@ -471,7 +549,7 @@ bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) {
(!shouldBypassMainWorldCSP &&
!csp->allowInlineScript(m_element, elementDocument->url(), nonce,
m_startLineNumber, sourceCode.source()))) {
- return false;
+ return CheckScriptResult::Abort;
}
if (m_isExternalScript) {
@@ -486,7 +564,7 @@ bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) {
resource->httpContentType() + "') is not executable, and "
"strict MIME type checking is "
"enabled."));
- return false;
+ return CheckScriptResult::Abort;
}
String mimeType = resource->httpContentType();
@@ -505,18 +583,18 @@ bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) {
UseCounter::count(frame, UseCounter::BlockedSniffingVideoToScript);
else if (mimeType == "text/csv")
UseCounter::count(frame, UseCounter::BlockedSniffingCSVToScript);
- return false;
+ return CheckScriptResult::Abort;
}
logScriptMIMEType(frame, resource, mimeType);
}
}
- // FIXME: Can this be moved earlier in the function?
- // Why are we ever attempting to execute scripts without a frame?
- if (!frame)
- return true;
+ return CheckScriptResult::Proceed;
+}
+AccessControlStatus ScriptLoader::computeAccessControlStatus(
+ const ScriptSourceCode& sourceCode) {
AccessControlStatus accessControlStatus = NotSharableCrossOrigin;
if (!m_isExternalScript) {
accessControlStatus = SharableCrossOrigin;
@@ -532,27 +610,45 @@ bool ScriptLoader::doExecuteScript(const ScriptSourceCode& sourceCode) {
accessControlStatus = SharableCrossOrigin;
}
}
+ return accessControlStatus;
+}
+
+template <typename Functor>
+void ScriptLoader::asCurrentScript(const Functor& functor) {
+ Document* elementDocument = &m_element->document();
+ Document* contextDocument = elementDocument->contextDocument();
+ LocalFrame* frame = contextDocument->frame();
+ if (!frame)
+ return;
- const bool isImportedScript = contextDocument != elementDocument;
// http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block
// step 2.3 with additional support for HTML imports.
+ const bool isImportedScript = contextDocument != elementDocument;
IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer(
m_isExternalScript || isImportedScript ? contextDocument : 0);
if (isHTMLScriptLoader(m_element) || isSVGScriptLoader(m_element))
contextDocument->pushCurrentScript(m_element);
- // Create a script from the script element node, using the script
- // block's source and the script block's type.
- // Note: This is where the script is compiled and actually executed.
- frame->script().executeScriptInMainWorld(sourceCode, accessControlStatus);
+ functor(frame->script());
if (isHTMLScriptLoader(m_element) || isSVGScriptLoader(m_element)) {
DCHECK(contextDocument->currentScript() == m_element);
contextDocument->popCurrentScript();
}
+}
- return true;
+void ScriptLoader::recordParserBlockedOnScriptExecutionSince(double startTime) {
+ // NOTE: we do not check m_willBeParserExecuted here, since
+ // m_willBeParserExecuted is false for inline scripts, and we want to
+ // include inline script execution time as part of parser blocked script
+ // execution time.
+ if (m_asyncExecType == ScriptRunner::None) {
+ DocumentParserTiming::from(m_element->document())
+ .recordParserBlockedOnScriptExecutionDuration(
+ monotonicallyIncreasingTime() - startTime,
+ wasCreatedDuringDocumentWrite());
+ }
}
void ScriptLoader::execute() {
« no previous file with comments | « third_party/WebKit/Source/core/dom/ScriptLoader.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698