bool HTMLScriptRunner::isPendingScriptReady(const PendingScript& script) { m_hasScriptsWaitingForResources = !m_document->isScriptExecutionReady(); if (m_hasScriptsWaitingForResources) return false; if (script.resource() && !script.resource()->isLoaded()) return false; return true; }
bool HTMLScriptRunner::isPendingScriptReady(const PendingScript& script) { m_hasScriptsWaitingForResources = !m_document->haveStylesheetsAndImportsLoaded(); if (m_hasScriptsWaitingForResources) return false; if (script.resource() && !script.resource()->isLoaded()) return false; return true; }
ScriptSourceCode HTMLScriptRunner::sourceFromPendingScript(const PendingScript& script, bool& errorOccurred) const { if (script.resource()) { errorOccurred = script.resource()->errorOccurred(); ASSERT(script.resource()->isLoaded()); return ScriptSourceCode(script.resource()); } errorOccurred = false; return ScriptSourceCode(script.element()->textContent(), documentURLForScriptExecution(m_document), script.startingPosition()); }
void HTMLScriptRunner::executePendingScriptAndDispatchEvent(PendingScript& pendingScript) { bool errorOccurred = false; ScriptSourceCode sourceCode = sourceFromPendingScript(pendingScript, errorOccurred); // Stop watching loads before executeScript to prevent recursion if the script reloads itself. if (pendingScript.resource() && pendingScript.watchingForLoad()) stopWatchingForLoad(pendingScript); if (!isExecutingScript()) Microtask::performCheckpoint(); // Clear the pending script before possible rentrancy from executeScript() RefPtr<Element> element = pendingScript.releaseElementAndClear(); if (ScriptLoader* scriptLoader = toScriptLoaderIfPossible(element.get())) { NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel); IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer(m_document); if (errorOccurred) scriptLoader->dispatchErrorEvent(); else { ASSERT(isExecutingScript()); scriptLoader->executeScript(sourceCode); element->dispatchEvent(createScriptLoadEvent()); } } ASSERT(!isExecutingScript()); }
void HTMLScriptRunner::executePendingScriptAndDispatchEvent(PendingScript& pendingScript, PendingScriptType pendingScriptType) { bool errorOccurred = false; ScriptSourceCode sourceCode = sourceFromPendingScript(pendingScript, errorOccurred); // Stop watching loads before executeScript to prevent recursion if the script reloads itself. if (pendingScript.resource() && pendingScript.watchingForLoad()) stopWatchingForLoad(pendingScript); if (!isExecutingScript()) { Microtask::performCheckpoint(); if (pendingScriptType == PendingScriptBlockingParser) { m_hasScriptsWaitingForResources = !m_document->isScriptExecutionReady(); // The parser cannot be unblocked as a microtask requested another resource if (m_hasScriptsWaitingForResources) return; } } // Clear the pending script before possible rentrancy from executeScript() RefPtr<Element> element = pendingScript.releaseElementAndClear(); if (ScriptLoader* scriptLoader = toScriptLoaderIfPossible(element.get())) { NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel); IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer(m_document); if (errorOccurred) scriptLoader->dispatchErrorEvent(); else { ASSERT(isExecutingScript()); scriptLoader->executeScript(sourceCode); element->dispatchEvent(createScriptLoadEvent()); } } ASSERT(!isExecutingScript()); }
void HTMLScriptRunner::requestDeferredScript(Element* element) { PendingScript pendingScript; if (!requestPendingScript(pendingScript, element)) return; ASSERT(pendingScript.resource()); m_scriptsToExecuteAfterParsing.append(pendingScript); }
PendingScript::PendingScript(const PendingScript& other) : ResourceOwner(other) , m_watchingForLoad(other.m_watchingForLoad) , m_element(other.m_element) , m_startingPosition(other.m_startingPosition) , m_streamer(other.m_streamer) { setScriptResource(other.resource()); }
HTMLScriptRunner::~HTMLScriptRunner() { // FIXME: Should we be passed a "done loading/parsing" callback sooner than destruction? if (m_parserBlockingScript.resource() && m_parserBlockingScript.watchingForLoad()) stopWatchingForLoad(m_parserBlockingScript); while (!m_scriptsToExecuteAfterParsing.isEmpty()) { PendingScript pendingScript = m_scriptsToExecuteAfterParsing.takeFirst(); if (pendingScript.resource() && pendingScript.watchingForLoad()) stopWatchingForLoad(pendingScript); } }
void HTMLScriptRunner::requestDeferredScript(Element* element) { PendingScript* pendingScript = PendingScript::create(nullptr, nullptr); if (!requestPendingScript(pendingScript, element)) return; if (m_document->frame() && !pendingScript->isReady()) { ScriptState* scriptState = ScriptState::forMainWorld(m_document->frame()); if (scriptState) ScriptStreamer::startStreaming(pendingScript, ScriptStreamer::Deferred, m_document->frame()->settings(), scriptState, m_document->loadingTaskRunner()); } ASSERT(pendingScript->resource()); m_scriptsToExecuteAfterParsing.append(pendingScript); }
bool ScriptStreamer::startStreamingInternal(PendingScript& script, Settings* settings, ScriptState* scriptState, PendingScript::Type scriptType) { ASSERT(isMainThread()); if (!settings || !settings->v8ScriptStreamingEnabled()) return false; if (settings->v8ScriptStreamingMode() == ScriptStreamingModeOnlyAsyncAndDefer && scriptType == PendingScript::ParsingBlocking) return false; ScriptResource* resource = script.resource(); if (resource->isLoaded()) return false; if (!resource->url().protocolIsInHTTPFamily()) return false; if (resource->resourceToRevalidate()) { // This happens e.g., during reloads. We're actually not going to load // the current Resource of the PendingScript but switch to another // Resource -> don't stream. return false; } // We cannot filter out short scripts, even if we wait for the HTTP headers // to arrive. In general, the web servers don't seem to send the // Content-Length HTTP header for scripts. if (!scriptState->contextIsValid()) return false; // Decide what kind of cached data we should produce while streaming. By // default, we generate the parser cache for streamed scripts, to emulate // the non-streaming behavior (see V8ScriptRunner::compileScript). v8::ScriptCompiler::CompileOptions compileOption = v8::ScriptCompiler::kProduceParserCache; if (settings->v8CacheOptions() == V8CacheOptionsCode) compileOption = v8::ScriptCompiler::kProduceCodeCache; // The Resource might go out of scope if the script is no longer // needed. This makes PendingScript notify the ScriptStreamer when it is // destroyed. script.setStreamer(adoptRef(new ScriptStreamer(resource, scriptType, settings->v8ScriptStreamingMode(), scriptState, compileOption))); return true; }
void HTMLScriptRunner::stopWatchingForLoad(PendingScript& pendingScript) { ASSERT(pendingScript.watchingForLoad()); m_host->stopWatchingForLoad(pendingScript.resource()); pendingScript.setWatchingForLoad(false); }
void HTMLScriptRunner::watchForLoad(PendingScript& pendingScript) { ASSERT(!pendingScript.watchingForLoad()); m_host->watchForLoad(pendingScript.resource()); pendingScript.setWatchingForLoad(true); }