Index: third_party/WebKit/Source/core/dom/PendingScript.cpp |
diff --git a/third_party/WebKit/Source/core/dom/PendingScript.cpp b/third_party/WebKit/Source/core/dom/PendingScript.cpp |
index 7ea074252620e6ed402a035c3bbe8bfceba0d48e..36891d53430be82b931e1f33a7faf12fa213a820 100644 |
--- a/third_party/WebKit/Source/core/dom/PendingScript.cpp |
+++ b/third_party/WebKit/Source/core/dom/PendingScript.cpp |
@@ -25,10 +25,15 @@ |
#include "core/dom/PendingScript.h" |
+#include "bindings/core/v8/ScriptController.h" |
#include "bindings/core/v8/ScriptSourceCode.h" |
#include "core/dom/Element.h" |
+#include "core/dom/ScriptLoader.h" |
+#include "core/dom/TaskRunnerHelper.h" |
+#include "core/frame/LocalFrame.h" |
#include "core/frame/SubresourceIntegrity.h" |
#include "platform/SharedBuffer.h" |
+#include "platform/instrumentation/tracing/TraceEvent.h" |
#include "wtf/CurrentTime.h" |
namespace blink { |
@@ -52,6 +57,7 @@ PendingScript::PendingScript(Element* element, |
const TextPosition& startingPosition, |
bool isForTesting) |
: m_watchingForLoad(false), |
+ m_readyState(resource ? kWaitingForResource : kReady), |
m_element(element), |
m_startingPosition(startingPosition), |
m_integrityFailure(false), |
@@ -99,7 +105,7 @@ void PendingScript::watchForLoad(PendingScriptClient* client) { |
m_watchingForLoad = true; |
m_client = client; |
if (isReady()) |
- m_client->pendingScriptFinished(this); |
+ client->pendingScriptFinished(this); |
} |
void PendingScript::stopWatchingForLoad() { |
@@ -121,6 +127,51 @@ Element* PendingScript::element() const { |
void PendingScript::streamingFinished() { |
checkState(); |
DCHECK(resource()); |
+ fetchFinished(); |
+} |
+ |
+void PendingScript::fetchFinished() { |
+ advanceReadyState(kWaitingForCompile); |
+ |
+ TRACE_EVENT_WITH_FLOW0("blink", "PendingScript compile", this, |
+ TRACE_EVENT_FLAG_FLOW_OUT); |
+ LocalFrame* frame = m_element ? m_element->document().frame() : nullptr; |
+ if (!frame) { |
+ // TODO(jbroman): A way of telling the client that it failed, without making |
+ // the client try again, would be great. |
+ compileFinished(); |
+ return; |
+ } |
+ |
+ ScriptState::Scope scope(ScriptState::forMainWorld(frame)); |
+ bool errorOccurred; |
+ ScriptSourceCode sourceCode = getSource(KURL(), errorOccurred); |
+ |
+ if (errorOccurred) { |
+ // TODO(jbroman): A way of telling the client that it failed, without making |
+ // the client try again, would be great. |
+ compileFinished(); |
+ return; |
+ } |
+ |
+ const bool isExternalScript = true; |
+ AccessControlStatus accessControlStatus = |
+ ScriptLoader::accessControlStatusForScript( |
+ isExternalScript, resource(), |
+ m_element->document().getSecurityOrigin()); |
+ m_compiledScript = |
+ frame->script().compileScriptInMainWorld(sourceCode, accessControlStatus); |
+ // TODO(jbroman): Can this fail? Yes, it can. |
+ // CHECK(m_compiledScript) << "no compiled script? :'("; |
+ TaskRunnerHelper::get(TaskType::Networking, frame) |
+ ->postTask(FROM_HERE, WTF::bind(&PendingScript::compileFinished, |
+ wrapPersistent(this))); |
+} |
+ |
+void PendingScript::compileFinished() { |
+ TRACE_EVENT_WITH_FLOW0("blink", "PendingScript compile", this, |
+ TRACE_EVENT_FLAG_FLOW_IN); |
+ advanceReadyState(kReady); |
if (m_client) |
m_client->pendingScriptFinished(this); |
} |
@@ -202,10 +253,12 @@ void PendingScript::notifyFinished(Resource* resource) { |
// If script streaming is in use, the client will be notified in |
// streamingFinished. |
- if (m_streamer) |
+ if (m_streamer) { |
+ advanceReadyState(kWaitingForStreaming); |
m_streamer->notifyFinished(resource); |
- else if (m_client) |
- m_client->pendingScriptFinished(this); |
+ } else { |
+ fetchFinished(); |
+ } |
} |
void PendingScript::notifyAppendData(ScriptResource* resource) { |
@@ -217,6 +270,7 @@ DEFINE_TRACE(PendingScript) { |
visitor->trace(m_element); |
visitor->trace(m_streamer); |
visitor->trace(m_client); |
+ visitor->trace(m_compiledScript); |
ResourceOwner<ScriptResource>::trace(visitor); |
MemoryCoordinatorClient::trace(visitor); |
} |
@@ -228,8 +282,12 @@ ScriptSourceCode PendingScript::getSource(const KURL& documentURL, |
errorOccurred = this->errorOccurred(); |
if (resource()) { |
DCHECK(resource()->isLoaded()); |
- if (m_streamer && !m_streamer->streamingSuppressed()) |
+ // Avoid consuming the streamed source code more than once. |
+ // TODO(jbroman): Update this if we don't always do the precompile step. |
+ if (m_streamer && !m_streamer->streamingSuppressed() && |
+ m_readyState < ReadyState::kReady) { |
return ScriptSourceCode(m_streamer, resource()); |
+ } |
return ScriptSourceCode(resource()); |
} |
@@ -240,17 +298,15 @@ ScriptSourceCode PendingScript::getSource(const KURL& documentURL, |
void PendingScript::setStreamer(ScriptStreamer* streamer) { |
DCHECK(!m_streamer); |
DCHECK(!m_watchingForLoad); |
+ DCHECK(!streamer->isFinished()); |
+ DCHECK_LT(m_readyState, kWaitingForStreaming); |
m_streamer = streamer; |
checkState(); |
} |
bool PendingScript::isReady() const { |
checkState(); |
- if (resource()) { |
- return resource()->isLoaded() && (!m_streamer || m_streamer->isFinished()); |
- } |
- |
- return true; |
+ return m_readyState == kReady; |
} |
bool PendingScript::errorOccurred() const { |