Bug 1938290 - Add a continuation mechanism for the parsers returning early due to there being a current script. r=peterv
Differential Revision: https://phabricator.services.mozilla.com/D233329
This commit is contained in:
@@ -883,6 +883,12 @@ bool nsContentSink::IsScriptExecutingImpl() {
|
||||
return !!mScriptLoader->GetCurrentScript();
|
||||
}
|
||||
|
||||
void nsContentSink::ContinueParsingDocumentAfterCurrentScriptImpl() {
|
||||
if (mScriptLoader) {
|
||||
mScriptLoader->ContinueParsingDocumentAfterCurrentScript();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult nsContentSink::WillParseImpl(void) {
|
||||
if (mRunsToCompletion || !mDocument) {
|
||||
return NS_OK;
|
||||
|
||||
@@ -105,6 +105,7 @@ class nsContentSink : public nsICSSLoaderObserver,
|
||||
void DidBuildModelImpl(bool aTerminated);
|
||||
void DropParserAndPerfHint(void);
|
||||
bool IsScriptExecutingImpl();
|
||||
void ContinueParsingDocumentAfterCurrentScriptImpl();
|
||||
|
||||
void NotifyAppend(nsIContent* aContent, uint32_t aStartIndex);
|
||||
|
||||
|
||||
@@ -207,6 +207,7 @@ ScriptLoader::ScriptLoader(Document* aDocument)
|
||||
mBlockingDOMContentLoaded(false),
|
||||
mLoadEventFired(false),
|
||||
mGiveUpEncoding(false),
|
||||
mContinueParsingDocumentAfterCurrentScript(false),
|
||||
mReporter(new ConsoleReportCollector()) {
|
||||
LOG(("ScriptLoader::ScriptLoader %p", this));
|
||||
|
||||
@@ -2721,7 +2722,8 @@ nsresult ScriptLoader::EvaluateScriptElement(ScriptLoadRequest* aRequest) {
|
||||
Document* ownerDoc =
|
||||
aRequest->GetScriptLoadContext()->GetScriptOwnerDocument();
|
||||
if (ownerDoc != mDocument) {
|
||||
// Willful violation of HTML5 as of 2010-12-01
|
||||
// https://html.spec.whatwg.org/#prepare-the-script-element step 16
|
||||
// as of 2025-01-15
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@@ -2749,6 +2751,23 @@ nsresult ScriptLoader::EvaluateScriptElement(ScriptLoadRequest* aRequest) {
|
||||
globalObject = scriptGlobal;
|
||||
}
|
||||
|
||||
// This mechanism is currently only used when the parser returns
|
||||
// early due to this script loader having a current script. However,
|
||||
// now that we have this, we could migrate continuing after a
|
||||
// parser-blocking script to this same mechanism. Not doing it right
|
||||
// away to reduce risk of introducing bugs.
|
||||
auto maybeContinueParser = MakeScopeExit([&] {
|
||||
if (mContinueParsingDocumentAfterCurrentScript) {
|
||||
mContinueParsingDocumentAfterCurrentScript = false;
|
||||
if (mDocument) {
|
||||
nsCOMPtr<nsIParser> parser = mDocument->CreatorParserOrNull();
|
||||
if (parser) {
|
||||
parser->ContinueInterruptedParsingAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Update our current script.
|
||||
// This must be destroyed after destroying nsAutoMicroTask, see:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1620505#c4
|
||||
|
||||
@@ -224,6 +224,11 @@ class ScriptLoader final : public JS::loader::ScriptLoaderInterface {
|
||||
*/
|
||||
nsIScriptElement* GetCurrentScript() { return mCurrentScript; }
|
||||
|
||||
void ContinueParsingDocumentAfterCurrentScript() {
|
||||
MOZ_ASSERT(mCurrentScript);
|
||||
mContinueParsingDocumentAfterCurrentScript = true;
|
||||
}
|
||||
|
||||
nsIScriptElement* GetCurrentParserInsertedScript() {
|
||||
return mCurrentParserInsertedScript;
|
||||
}
|
||||
@@ -817,6 +822,7 @@ class ScriptLoader final : public JS::loader::ScriptLoaderInterface {
|
||||
bool mBlockingDOMContentLoaded;
|
||||
bool mLoadEventFired;
|
||||
bool mGiveUpEncoding;
|
||||
bool mContinueParsingDocumentAfterCurrentScript;
|
||||
|
||||
TimeDuration mMainThreadParseTime;
|
||||
|
||||
|
||||
@@ -792,8 +792,6 @@ void nsXMLContentSink::SetDocumentCharset(NotNull<const Encoding*> aEncoding) {
|
||||
|
||||
nsISupports* nsXMLContentSink::GetTarget() { return ToSupports(mDocument); }
|
||||
|
||||
bool nsXMLContentSink::IsScriptExecuting() { return IsScriptExecutingImpl(); }
|
||||
|
||||
nsresult nsXMLContentSink::FlushText(bool aReleaseTextNode) {
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
||||
@@ -69,7 +69,10 @@ class nsXMLContentSink : public nsContentSink,
|
||||
virtual void FlushPendingNotifications(mozilla::FlushType aType) override;
|
||||
virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override;
|
||||
virtual nsISupports* GetTarget() override;
|
||||
virtual bool IsScriptExecuting() override;
|
||||
bool IsScriptExecuting() override { return IsScriptExecutingImpl(); }
|
||||
void ContinueParsingDocumentAfterCurrentScript() override {
|
||||
ContinueParsingDocumentAfterCurrentScriptImpl();
|
||||
}
|
||||
virtual void ContinueInterruptedParsingAsync() override;
|
||||
bool IsPrettyPrintXML() const override { return mPrettyPrintXML; }
|
||||
bool IsPrettyPrintHasSpecialRoot() const override {
|
||||
|
||||
@@ -516,6 +516,8 @@ void nsHtml5TreeOpExecutor::RunFlushLoop() {
|
||||
|
||||
if (mRunFlushLoopOnStack) {
|
||||
// There's already a RunFlushLoop() on the call stack.
|
||||
// The instance of RunFlushLoop() already on the stack is
|
||||
// expected to ensure that we don't stall.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -544,18 +546,26 @@ void nsHtml5TreeOpExecutor::RunFlushLoop() {
|
||||
|
||||
if (!parserKungFuDeathGrip->IsParserEnabled()) {
|
||||
// The parser is blocked.
|
||||
// Whatever blocked the parser is responsible for ensuring that
|
||||
// we don't stall.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFlushState != eNotFlushing) {
|
||||
// XXX Can this happen? In case it can, let's avoid crashing.
|
||||
// It's not clear whether this case can ever happen. It's not
|
||||
// supposed to, but in case this can happen, let's return
|
||||
// early to avoid an even worse state. In case this happens,
|
||||
// there in no obvious other mechanism to prevent stalling,
|
||||
// so let's call `ContinueInterruptedParsingAsync()` to
|
||||
// make sure we don't stall.
|
||||
nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
// If there are scripts executing, then the content sink is jumping the gun
|
||||
// (probably due to a synchronous XMLHttpRequest) and will re-enable us
|
||||
// later, see bug 460706.
|
||||
// If there are scripts executing, this is probably due to a synchronous
|
||||
// XMLHttpRequest, see bug 460706 and 1938290.
|
||||
if (IsScriptExecuting()) {
|
||||
ContinueParsingDocumentAfterCurrentScript();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +161,10 @@ class nsHtml5TreeOpExecutor final
|
||||
|
||||
bool IsScriptExecuting() override { return IsScriptExecutingImpl(); }
|
||||
|
||||
void ContinueParsingDocumentAfterCurrentScript() override {
|
||||
ContinueParsingDocumentAfterCurrentScriptImpl();
|
||||
}
|
||||
|
||||
// Not from interface
|
||||
|
||||
void SetStreamParser(nsHtml5StreamParser* aStreamParser) {
|
||||
|
||||
@@ -28,12 +28,8 @@ namespace mozilla {
|
||||
class Encoding;
|
||||
}
|
||||
|
||||
#define NS_ICONTENT_SINK_IID \
|
||||
{ \
|
||||
0xcf9a7cbb, 0xfcbc, 0x4e13, { \
|
||||
0x8e, 0xf5, 0x18, 0xef, 0x2d, 0x3d, 0x58, 0x29 \
|
||||
} \
|
||||
}
|
||||
#define NS_ICONTENT_SINK_IID \
|
||||
{0xcf9a7cbb, 0xfcbc, 0x4e13, {0x8e, 0xf5, 0x18, 0xef, 0x2d, 0x3d, 0x58, 0x29}}
|
||||
|
||||
class nsIContentSink : public nsISupports {
|
||||
protected:
|
||||
@@ -130,6 +126,8 @@ class nsIContentSink : public nsISupports {
|
||||
*/
|
||||
virtual bool IsScriptExecuting() { return false; }
|
||||
|
||||
virtual void ContinueParsingDocumentAfterCurrentScript() {};
|
||||
|
||||
/**
|
||||
* Posts a runnable that continues parsing.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user