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::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.cachedScript() && pendingScript.watchingForLoad()) stopWatchingForLoad(pendingScript); if (!isExecutingScript()) { #if ENABLE(CUSTOM_ELEMENTS) CustomElementRegistry::deliverAllLifecycleCallbacks(); #endif MutationObserver::deliverAllMutations(); } // Clear the pending script before possible rentrancy from executeScript() RefPtr<Element> element = pendingScript.releaseElementAndClear(); if (ScriptElement* scriptElement = toScriptElement(element.get())) { NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel); IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer(m_document); if (errorOccurred) scriptElement->dispatchErrorEvent(); else { ASSERT(isExecutingScript()); scriptElement->executeScript(sourceCode); element->dispatchEvent(createScriptLoadEvent()); } } ASSERT(!isExecutingScript()); }
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 HTMLDocumentParser::watchForLoad(PendingScript& pendingScript) { ASSERT(!pendingScript.isLoaded()); // setClient would call notifyFinished if the load were complete. // Callers do not expect to be re-entered from this call, so they should // not an already-loaded PendingScript. pendingScript.setClient(this); }
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; }
bool HTMLScriptRunner::isPendingScriptReady(const PendingScript& script) { m_hasScriptsWaitingForStylesheets = !m_document->haveStylesheetsLoaded(); if (m_hasScriptsWaitingForStylesheets) return false; if (script.cachedScript() && !script.cachedScript()->isLoaded()) return false; return true; }
void HTMLScriptRunner::requestDeferredScript(Element* element) { PendingScript pendingScript; if (!requestPendingScript(pendingScript, element)) return; ASSERT(pendingScript.cachedScript()); m_scriptsToExecuteAfterParsing.append(pendingScript); }
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; }
void ScriptElement::executeScriptForScriptRunner(PendingScript& pendingScript) { if (auto* loadableScript = pendingScript.loadableScript()) executeScriptAndDispatchEvent(*loadableScript); else { ASSERT(!pendingScript.wasErrored()); executeScript(ScriptSourceCode(scriptContent(), m_element.document().url(), pendingScript.startingPosition())); dispatchLoadEvent(); } }
ScriptSourceCode HTMLScriptRunner::sourceFromPendingScript(const PendingScript& script, bool& errorOccurred) const { if (script.cachedScript()) { errorOccurred = script.cachedScript()->errorOccurred(); ASSERT(script.cachedScript()->isLoaded()); return ScriptSourceCode(script.cachedScript()); } errorOccurred = false; return ScriptSourceCode(script.element()->textContent(), documentURLForScriptExecution(m_document), script.startingPosition()); }
void ScriptRunner::notifyFinished(PendingScript& pendingScript) { if (pendingScript.element().willExecuteInOrder()) ASSERT(!m_scriptsToExecuteInOrder.isEmpty()); else { ASSERT(m_pendingAsyncScripts.contains(pendingScript)); m_scriptsToExecuteSoon.append(m_pendingAsyncScripts.take(pendingScript)->ptr()); } pendingScript.clearClient(); m_timer.startOneShot(0); }
HTMLScriptRunner::~HTMLScriptRunner() { // FIXME: Should we be passed a "done loading/parsing" callback sooner than destruction? if (m_parsingBlockingScript.cachedScript() && m_parsingBlockingScript.watchingForLoad()) stopWatchingForLoad(m_parsingBlockingScript); while (!m_scriptsToExecuteAfterParsing.isEmpty()) { PendingScript pendingScript = m_scriptsToExecuteAfterParsing.takeFirst(); if (pendingScript.cachedScript() && pendingScript.watchingForLoad()) stopWatchingForLoad(pendingScript); } }
bool HTMLScriptRunner::requestPendingScript(PendingScript& pendingScript, Element* script) const { ASSERT(!pendingScript.element()); pendingScript.setElement(script); // This should correctly return 0 for empty or invalid srcValues. CachedScript* cachedScript = toScriptElement(script)->cachedScript().get(); if (!cachedScript) { notImplemented(); // Dispatch error event. return false; } pendingScript.setCachedScript(cachedScript); return true; }
bool HTMLScriptRunner::requestPendingScript(PendingScript& pendingScript, Element* script) const { ASSERT(!pendingScript.element()); pendingScript.setElement(script); // This should correctly return 0 for empty or invalid srcValues. ScriptResource* resource = toScriptLoaderIfPossible(script)->resource().get(); if (!resource) { notImplemented(); // Dispatch error event. return false; } pendingScript.setScriptResource(resource); return true; }
void HTMLScriptRunner::detach() { if (!m_document) return; m_parserBlockingScript->stopWatchingForLoad(); m_parserBlockingScript->releaseElementAndClear(); while (!m_scriptsToExecuteAfterParsing.isEmpty()) { PendingScript* pendingScript = m_scriptsToExecuteAfterParsing.takeFirst(); pendingScript->stopWatchingForLoad(); pendingScript->releaseElementAndClear(); } m_document = nullptr; }
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); }
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()); }
bool HTMLScriptRunner::requestPendingScript(PendingScript& pendingScript, Element* script) const { ASSERT(!pendingScript.element()); const AtomicString& srcValue = script->getAttribute(srcAttr); // Allow the host to disllow script loads (using the XSSAuditor, etc.) if (!m_host->shouldLoadExternalScriptFromSrc(srcValue)) return false; // FIXME: We need to resolve the url relative to the element. if (!script->dispatchBeforeLoadEvent(srcValue)) return false; pendingScript.adoptElement(script); // This should correctly return 0 for empty or invalid srcValues. CachedScript* cachedScript = m_document->cachedResourceLoader()->requestScript(srcValue, toScriptElement(script)->scriptCharset()); if (!cachedScript) { notImplemented(); // Dispatch error event. return false; } pendingScript.setCachedScript(cachedScript); return true; }
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::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.cachedScript() && pendingScript.watchingForLoad()) stopWatchingForLoad(pendingScript); // WebERA: Insert HB relation between the execution of a pending script and the load of the script if (HBIsCurrentEventActionValid() && pendingScript.cachedScript() && pendingScript.cachedScript()->isLoaded() && pendingScript.cachedScript()->getLoadingEventAction() != 0) { HBAddExplicitArc(pendingScript.cachedScript()->getLoadingEventAction(), HBCurrentEventAction()); } // Clear the pending script before possible rentrancy from executeScript() RefPtr<Element> element = pendingScript.releaseElementAndClear(); if (ScriptElement* scriptElement = toScriptElement(element.get())) { NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel); IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer(m_document); if (errorOccurred) scriptElement->dispatchErrorEvent(); else { ASSERT(isExecutingScript()); scriptElement->executeScript(sourceCode); element->dispatchEvent(createScriptLoadEvent()); } } ASSERT(!m_scriptNestingLevel); }
bool HTMLScriptRunner::requestPendingScript(PendingScript& pendingScript, Element* script) const { ASSERT(!pendingScript.element()); if (V8IsolatedContext::getEntered() != 0) { std::ostringstream wid; int worldID = V8IsolatedContext::getEntered()->getWorldID(); wid << worldID; std::string aclid = wid.str()+";"; std::string aclname = "ACL"; std::string ROACLname = "ROACL"; ExceptionCode ec; if (worldID!=0) { script->setAttribute("worldID",wid.str().c_str(),ec,worldID,false); script->setAttribute(aclname.c_str(),aclid.c_str(),ec,worldID,false); script->setAttribute(ROACLname.c_str(),aclid.c_str(),ec,worldID,false); } } const AtomicString& srcValue = script->getAttribute(srcAttr); // Allow the host to disllow script loads (using the XSSAuditor, etc.) if (!m_host->shouldLoadExternalScriptFromSrc(srcValue)) return false; // FIXME: We need to resolve the url relative to the element. if (!script->dispatchBeforeLoadEvent(srcValue)) return false; pendingScript.adoptElement(script); // This should correctly return 0 for empty or invalid srcValues. CachedScript* cachedScript = m_document->docLoader()->requestScript(srcValue, toScriptElement(script)->scriptCharset()); if (!cachedScript) { notImplemented(); // Dispatch error event. return false; } pendingScript.setCachedScript(cachedScript); return true; }
void HTMLScriptRunner::executePendingScriptAndDispatchEvent(PendingScript& pendingScript) { bool errorOccurred = false; ScriptSourceCode sourceCode = sourceFromPendingScript(pendingScript, errorOccurred); // Clear the pending script before possible rentrancy from executeScript() RefPtr<Element> scriptElement = pendingScript.releaseElementAndClear(); { NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel); if (errorOccurred) scriptElement->dispatchEvent(createScriptErrorEvent()); else { executeScript(scriptElement.get(), sourceCode); scriptElement->dispatchEvent(createScriptLoadEvent()); } } ASSERT(!m_scriptNestingLevel); }
void HTMLScriptRunner::stopWatchingForLoad(PendingScript& pendingScript) { ASSERT(pendingScript.watchingForLoad()); m_host->stopWatchingForLoad(pendingScript.cachedScript()); pendingScript.setWatchingForLoad(false); }
void HTMLScriptRunner::watchForLoad(PendingScript& pendingScript) { ASSERT(!pendingScript.watchingForLoad()); m_host->watchForLoad(pendingScript.cachedScript()); pendingScript.setWatchingForLoad(true); }
void HTMLScriptRunner::stopWatchingForLoad(PendingScript& pendingScript) { ASSERT(pendingScript.watchingForLoad()); m_host.stopWatchingForLoad(pendingScript); }
void HTMLDocumentParser::stopWatchingForLoad(PendingScript& pendingScript) { pendingScript.clearClient(); }