Bug 1443553: Devirtualize BeginUpdate, FlushPendingNotifications, CreatorParserOrNull. r?smaug
MozReview-Commit-ID: FzPcHcyzJ02
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1476,16 +1476,19 @@ nsIDocument::nsIDocument()
mDidCallBeginLoad(false),
mBufferingCSPViolations(false),
mAllowPaymentRequest(false),
mEncodingMenuDisabled(false),
mIsShadowDOMEnabled(false),
mIsSVGGlyphsDocument(false),
mAllowUnsafeHTML(false),
mInDestructor(false),
+ mIsGoingAway(false),
+ mInXBLUpdate(false),
+ mNeedsReleaseAfterStackRefCntRelease(false),
mIsScopedStyleEnabled(eScopedStyle_Unknown),
mCompatMode(eCompatibility_FullStandards),
mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
mStyleBackendType(StyleBackendType::None),
#ifdef MOZILLA_INTERNAL_API
mVisibilityState(dom::VisibilityState::Hidden),
#else
mDummy(0),
@@ -1508,47 +1511,46 @@ nsIDocument::nsIDocument()
mInSyncOperationCount(0),
mBlockDOMContentLoaded(0),
mUseCounters(0),
mChildDocumentUseCounters(0),
mNotifiedPageForUseCounter(0),
mIncCounters(),
mUserHasInteracted(false),
mUserHasActivatedInteraction(false),
+ mStackRefCnt(0),
+ mUpdateNestLevel(0),
mServoRestyleRootDirtyBits(0),
mThrowOnDynamicMarkupInsertionCounter(0),
mIgnoreOpensDuringUnloadCounter(0)
{
SetIsInDocument();
for (auto& cnt : mIncCounters) {
cnt = 0;
}
}
nsDocument::nsDocument(const char* aContentType)
: nsIDocument()
, mSubDocuments(nullptr)
, mFlashClassification(FlashClassification::Unclassified)
, mHeaderData(nullptr)
- , mIsGoingAway(false)
, mMayHaveTitleElement(false)
, mHasWarnedAboutBoxObjects(false)
, mDelayFrameLoaderInitialization(false)
, mSynchronousDOMContentLoaded(false)
- , mInXBLUpdate(false)
, mParserAborted(false)
, mCurrentOrientationAngle(0)
, mCurrentOrientationType(OrientationType::Portrait_primary)
, mSSApplicableStateNotificationPending(false)
, mReportedUseCounters(false)
, mStyleSetFilled(false)
, mPendingFullscreenRequests(0)
, mXMLDeclarationBits(0)
, mBoxObjectTable(nullptr)
- , mUpdateNestLevel(0)
, mOnloadBlockCount(0)
, mAsyncOnloadBlockCount(0)
#ifdef DEBUG
, mStyledLinksCleared(false)
#endif
, mPreloadPictureDepth(0)
, mScrolledToRefAlready(0)
, mChangeScrollPosWhenScrollingToRef(0)
@@ -1557,18 +1559,16 @@ nsDocument::nsDocument(const char* aCont
, mValidHeight(false)
, mAutoSize(false)
, mAllowZoom(false)
, mAllowDoubleTapZoom(false)
, mValidScaleFloat(false)
, mValidMaxScale(false)
, mScaleStrEmpty(false)
, mWidthStrEmpty(false)
- , mStackRefCnt(0)
- , mNeedsReleaseAfterStackRefCntRelease(false)
, mMaybeServiceWorkerControlled(false)
#ifdef DEBUG
, mWillReparent(false)
#endif
, mDOMLoadingSet(false)
, mDOMInteractiveSet(false)
, mDOMCompleteSet(false)
, mAutoFocusFired(false)
@@ -3067,23 +3067,16 @@ nsDocument::InitCSP(nsIChannel* aChannel
// stop! ERROR page!
aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
}
}
ApplySettingsFromCSP(false);
return NS_OK;
}
-already_AddRefed<nsIParser>
-nsDocument::CreatorParserOrNull()
-{
- nsCOMPtr<nsIParser> parser = mParser;
- return parser.forget();
-}
-
void
nsDocument::StopDocumentLoad()
{
if (mParser) {
mParserAborted = true;
mParser->Terminate();
}
}
@@ -5169,17 +5162,17 @@ nsDocument::MaybeEndOutermostXBLUpdate()
&nsDocument::MaybeEndOutermostXBLUpdate);
}
nsContentUtils::AddScriptRunner(mMaybeEndOutermostXBLUpdateRunner);
}
}
}
void
-nsDocument::BeginUpdate(nsUpdateType aUpdateType)
+nsIDocument::BeginUpdate(nsUpdateType aUpdateType)
{
// If the document is going away, then it's probably okay to do things to it
// in the wrong DocGroup. We're unlikely to run JS or do anything else
// observable at this point. We reach this point when cycle collecting a
// <link> element and the unlink code removes a style sheet.
if (mDocGroup && !mIsGoingAway && !mInUnlinkOrDeletion && !mIgnoreDocGroupMismatches) {
mDocGroup->ValidateAccess();
}
@@ -7598,17 +7591,17 @@ nsIDocument::CreateEvent(const nsAString
}
WidgetEvent* e = ev->WidgetEventPtr();
e->mFlags.mBubbles = false;
e->mFlags.mCancelable = false;
return ev.forget();
}
void
-nsDocument::FlushPendingNotifications(FlushType aType)
+nsIDocument::FlushPendingNotifications(FlushType aType)
{
nsDocumentOnStack dos(this);
// We need to flush the sink for non-HTML documents (because the XML
// parser still does insertion with deferred notifications). We
// also need to flush the sink if this is a layout-related flush, to
// make sure that layout is started as needed. But we can skip that
// part if we have no presshell or if it's already done an initial
@@ -8027,17 +8020,17 @@ nsDocument::CreateElem(const nsAString&
nsCOMPtr<Element> element;
nsresult rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
NOT_FROM_PARSER, aIs);
return NS_SUCCEEDED(rv) ? element.forget() : nullptr;
}
bool
-nsDocument::IsSafeToFlush() const
+nsIDocument::IsSafeToFlush() const
{
nsIPresShell* shell = GetShell();
if (!shell)
return true;
return shell->IsSafeToFlush();
}
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -361,18 +361,16 @@ public:
virtual void SetDocumentURI(nsIURI* aURI) override;
virtual void SetChromeXHRDocURI(nsIURI* aURI) override;
virtual void SetChromeXHRDocBaseURI(nsIURI* aURI) override;
virtual void ApplySettingsFromCSP(bool aSpeculative) override;
- virtual already_AddRefed<nsIParser> CreatorParserOrNull() override;
-
/**
* Set the principal responsible for this document.
*/
virtual void SetPrincipal(nsIPrincipal *aPrincipal) override;
/**
* Set the Content-Type of this document.
*/
@@ -485,26 +483,22 @@ public:
/**
* Add/Remove an element to the document's id and name hashes
*/
virtual void AddToIdTable(Element* aElement, nsAtom* aId) override;
virtual void RemoveFromIdTable(Element* aElement, nsAtom* aId) override;
virtual void AddToNameTable(Element* aElement, nsAtom* aName) override;
virtual void RemoveFromNameTable(Element* aElement, nsAtom* aName) override;
- // Observation hooks used to propagate notifications to document
- // observers.
- virtual void BeginUpdate(nsUpdateType aUpdateType) override;
virtual void EndUpdate(nsUpdateType aUpdateType) override;
virtual void BeginLoad() override;
virtual void EndLoad() override;
virtual void SetReadyStateInternal(ReadyState rs) override;
- virtual void FlushPendingNotifications(mozilla::FlushType aType) final override;
virtual void FlushExternalResources(mozilla::FlushType aType) override;
virtual void SetXMLDeclaration(const char16_t *aVersion,
const char16_t *aEncoding,
const int32_t aStandalone) override;
virtual void GetXMLDeclaration(nsAString& aVersion,
nsAString& aEncoding,
nsAString& Standalone) override;
virtual bool IsScriptEnabled() override;
@@ -919,30 +913,16 @@ public:
const nsAString& aQualifiedName,
const mozilla::dom::ElementCreationOptionsOrString& aOptions,
mozilla::ErrorResult& rv) override;
virtual void UnblockDOMContentLoaded() override;
protected:
friend class nsNodeUtils;
- friend class nsDocumentOnStack;
-
- void IncreaseStackRefCnt()
- {
- ++mStackRefCnt;
- }
-
- void DecreaseStackRefCnt()
- {
- if (--mStackRefCnt == 0 && mNeedsReleaseAfterStackRefCntRelease) {
- mNeedsReleaseAfterStackRefCntRelease = false;
- NS_RELEASE_THIS();
- }
- }
/**
* Check that aId is not empty and log a message to the console
* service if it is.
* @returns true if aId looks correct, false otherwise.
*/
inline bool CheckGetElementByIdArg(const nsAString& aId)
{
@@ -998,19 +978,16 @@ public:
protected:
void RemoveDocStyleSheetsFromStyleSets();
void RemoveStyleSheetsFromStyleSets(
const nsTArray<RefPtr<mozilla::StyleSheet>>& aSheets,
mozilla::SheetType aType);
void ResetStylesheetsToURI(nsIURI* aURI);
void FillStyleSet(mozilla::StyleSetHandle aStyleSet);
- // Return whether all the presshells for this document are safe to flush
- bool IsSafeToFlush() const;
-
void DispatchPageTransition(mozilla::dom::EventTarget* aDispatchTarget,
const nsAString& aType,
bool aPersisted);
virtual nsPIDOMWindowOuter* GetWindowInternal() const override;
virtual nsIScriptGlobalObject* GetScriptHandlingObjectInternal() const override;
virtual bool InternalAllowXULXBL() override;
@@ -1053,25 +1030,16 @@ protected:
// the classification lists and the classification of parent documents.
mozilla::dom::FlashClassification ComputeFlashClassification();
PLDHashTable *mSubDocuments;
// Array of owning references to all children
nsAttrAndChildArray mChildren;
- // Pointer to our parser if we're currently in the process of being
- // parsed into.
- nsCOMPtr<nsIParser> mParser;
-
- // Weak reference to our sink for in case we no longer have a parser. This
- // will allow us to flush out any pending stuff from the sink even if
- // EndLoad() has already happened.
- nsWeakPtr mWeakSink;
-
nsTArray<RefPtr<mozilla::StyleSheet>> mOnDemandBuiltInUASheets;
nsTArray<RefPtr<mozilla::StyleSheet>> mAdditionalSheets[AdditionalSheetTypeCount];
// Array of intersection observers
nsTHashtable<nsPtrHashKey<mozilla::dom::DOMIntersectionObserver>>
mIntersectionObservers;
// Tracker for animations that are waiting to start.
@@ -1104,31 +1072,26 @@ public:
RefPtr<mozilla::dom::ScriptLoader> mScriptLoader;
nsDocHeaderData* mHeaderData;
nsClassHashtable<nsStringHashKey, nsRadioGroupStruct> mRadioGroups;
// Recorded time of change to 'loading' state.
mozilla::TimeStamp mLoadingTimeStamp;
- // True if the document has been detached from its content viewer.
- bool mIsGoingAway:1;
-
// True if this document has ever had an HTML or SVG <title> element
// bound to it
bool mMayHaveTitleElement:1;
bool mHasWarnedAboutBoxObjects:1;
bool mDelayFrameLoaderInitialization:1;
bool mSynchronousDOMContentLoaded:1;
- bool mInXBLUpdate:1;
-
// Parser aborted. True if the parser of this document was forcibly
// terminated instead of letting it finish at its own pace.
bool mParserAborted:1;
friend class nsCallRequestFullScreen;
// ScreenOrientation "pending promise" as described by
// http://www.w3.org/TR/screen-orientation/
@@ -1158,19 +1121,16 @@ public:
uint8_t mXMLDeclarationBits;
nsRefPtrHashtable<nsPtrHashKey<nsIContent>, mozilla::dom::BoxObject>* mBoxObjectTable;
// A document "without a browsing context" that owns the content of
// HTMLTemplateElement.
nsCOMPtr<nsIDocument> mTemplateContentsOwner;
- // Our update nesting level
- uint32_t mUpdateNestLevel;
-
// The application cache that this document is associated with, if
// any. This can change during the lifetime of the document.
nsCOMPtr<nsIApplicationCache> mApplicationCache;
nsCOMPtr<nsIContent> mFirstBaseNodeWithHref;
RefPtr<nsDOMNavigationTiming> mTiming;
private:
@@ -1284,19 +1244,16 @@ private:
bool mValidWidth, mValidHeight;
mozilla::LayoutDeviceToScreenScale mScaleMinFloat;
mozilla::LayoutDeviceToScreenScale mScaleMaxFloat;
mozilla::LayoutDeviceToScreenScale mScaleFloat;
mozilla::CSSToLayoutDeviceScale mPixelRatio;
bool mAutoSize, mAllowZoom, mAllowDoubleTapZoom, mValidScaleFloat, mValidMaxScale, mScaleStrEmpty, mWidthStrEmpty;
mozilla::CSSSize mViewportSize;
- nsrefcnt mStackRefCnt;
- bool mNeedsReleaseAfterStackRefCntRelease;
-
// Set to true when the document is possibly controlled by the ServiceWorker.
// Used to prevent multiple requests to ServiceWorkerManager.
bool mMaybeServiceWorkerControlled;
// We lazily calculate declaration blocks for SVG elements
// with mapped attributes in Servo mode. This list contains all elements which
// need lazy resolution
nsTHashtable<nsPtrHashKey<nsSVGElement>> mLazySVGPresElements;
@@ -1312,21 +1269,21 @@ private:
bool mDOMInteractiveSet : 1;
bool mDOMCompleteSet : 1;
bool mAutoFocusFired : 1;
};
class nsDocumentOnStack
{
public:
- explicit nsDocumentOnStack(nsDocument* aDoc) : mDoc(aDoc)
+ explicit nsDocumentOnStack(nsIDocument* aDoc) : mDoc(aDoc)
{
mDoc->IncreaseStackRefCnt();
}
~nsDocumentOnStack()
{
mDoc->DecreaseStackRefCnt();
}
private:
- nsDocument* mDoc;
+ nsIDocument* mDoc;
};
#endif /* nsDocument_h___ */
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -205,16 +205,17 @@ enum DocumentFlavor {
// RTL locale: specific to the XUL localedir attribute
#define NS_DOCUMENT_STATE_RTL_LOCALE NS_DEFINE_EVENT_STATE_MACRO(0)
// Window activation status
#define NS_DOCUMENT_STATE_WINDOW_INACTIVE NS_DEFINE_EVENT_STATE_MACRO(1)
// Some function forward-declarations
class nsContentList;
+class nsDocumentOnStack;
//----------------------------------------------------------------------
// Document interface. This is implemented by all document objects in
// Gecko.
class nsIDocument : public nsINode,
public mozilla::dom::DocumentOrShadowRoot,
public mozilla::dom::DispatcherTrait
@@ -368,17 +369,21 @@ public:
*/
virtual void SetChromeXHRDocBaseURI(nsIURI* aURI) = 0;
/**
* Set referrer policy and upgrade-insecure-requests flags
*/
virtual void ApplySettingsFromCSP(bool aSpeculative) = 0;
- virtual already_AddRefed<nsIParser> CreatorParserOrNull() = 0;
+ already_AddRefed<nsIParser> CreatorParserOrNull()
+ {
+ nsCOMPtr<nsIParser> parser = mParser;
+ return parser.forget();
+ }
/**
* Return the referrer policy of the document. Return "default" if there's no
* valid meta referrer tag found in the document.
*/
ReferrerPolicyEnum GetReferrerPolicy() const
{
return mReferrerPolicy;
@@ -909,16 +914,19 @@ public:
}
nsIPresShell* GetObservingShell() const
{
return mPresShell && mPresShell->IsObservingDocument()
? mPresShell : nullptr;
}
+ // Return whether the presshell for this document is safe to flush.
+ bool IsSafeToFlush() const;
+
nsPresContext* GetPresContext() const
{
nsIPresShell* shell = GetShell();
return shell ? shell->GetPresContext() : nullptr;
}
bool HasShellOrBFCacheEntry() const
{
@@ -1675,18 +1683,19 @@ public:
* return false if the observer cannot be found.
*/
bool RemoveObserver(nsIDocumentObserver* aObserver);
// Observation hooks used to propagate notifications to document observers.
// BeginUpdate must be called before any batch of modifications of the
// content model or of style data, EndUpdate must be called afterward.
// To make this easy and painless, use the mozAutoDocUpdate helper class.
- virtual void BeginUpdate(nsUpdateType aUpdateType) = 0;
+ void BeginUpdate(nsUpdateType aUpdateType);
virtual void EndUpdate(nsUpdateType aUpdateType) = 0;
+
virtual void BeginLoad() = 0;
virtual void EndLoad() = 0;
enum ReadyState { READYSTATE_UNINITIALIZED = 0, READYSTATE_LOADING = 1, READYSTATE_INTERACTIVE = 3, READYSTATE_COMPLETE = 4};
virtual void SetReadyStateInternal(ReadyState rs) = 0;
ReadyState GetReadyStateEnum()
{
return mReadyState;
@@ -1710,17 +1719,17 @@ public:
mozilla::css::Rule* aStyleRule);
void StyleRuleRemoved(mozilla::StyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule);
/**
* Flush notifications for this document and its parent documents
* (since those may affect the layout of this one).
*/
- virtual void FlushPendingNotifications(mozilla::FlushType aType) = 0;
+ void FlushPendingNotifications(mozilla::FlushType aType);
/**
* Calls FlushPendingNotifications on any external resources this document
* has. If this document has no external resources or is an external resource
* itself this does nothing. This should only be called with
* aType >= FlushType::Style.
*/
virtual void FlushExternalResources(mozilla::FlushType aType) = 0;
@@ -3221,16 +3230,31 @@ private:
// Lazy-initialization to have mDocGroup initialized in prior to the
// SelectorCaches.
// FIXME(emilio): We can use a single cache when all CSSOM methods are
// implemented for the Servo backend.
mozilla::UniquePtr<SelectorCache> mServoSelectorCache;
mozilla::UniquePtr<SelectorCache> mGeckoSelectorCache;
protected:
+ friend class nsDocumentOnStack;
+
+ void IncreaseStackRefCnt()
+ {
+ ++mStackRefCnt;
+ }
+
+ void DecreaseStackRefCnt()
+ {
+ if (--mStackRefCnt == 0 && mNeedsReleaseAfterStackRefCntRelease) {
+ mNeedsReleaseAfterStackRefCntRelease = false;
+ NS_RELEASE_THIS();
+ }
+ }
+
~nsIDocument();
nsPropertyTable* GetExtraPropertyTable(uint16_t aCategory);
// Never ever call this. Only call GetWindow!
virtual nsPIDOMWindowOuter* GetWindowInternal() const = 0;
// Never ever call this. Only call GetScriptHandlingObject!
virtual nsIScriptGlobalObject* GetScriptHandlingObjectInternal() const = 0;
@@ -3555,17 +3579,24 @@ protected:
// True if this document is for an SVG-in-OpenType font.
bool mIsSVGGlyphsDocument : 1;
// True if unsafe HTML fragments should be allowed in chrome-privileged
// documents.
bool mAllowUnsafeHTML : 1;
// True if the document is being destroyed.
- bool mInDestructor:1;
+ bool mInDestructor: 1;
+
+ // True if the document has been detached from its content viewer.
+ bool mIsGoingAway: 1;
+
+ bool mInXBLUpdate: 1;
+
+ bool mNeedsReleaseAfterStackRefCntRelease: 1;
// Whether <style scoped> support is enabled in this document.
enum { eScopedStyle_Unknown, eScopedStyle_Disabled, eScopedStyle_Enabled };
unsigned int mIsScopedStyleEnabled : 2;
// Compatibility mode
nsCompatibility mCompatMode;
@@ -3745,16 +3776,30 @@ protected:
nsTArray<nsCOMPtr<nsIRunnable>> mBufferedCSPViolations;
// List of ancestor principals. This is set at the point a document
// is connected to a docshell and not mutated thereafter.
nsTArray<nsCOMPtr<nsIPrincipal>> mAncestorPrincipals;
// List of ancestor outerWindowIDs that correspond to the ancestor principals.
nsTArray<uint64_t> mAncestorOuterWindowIDs;
+ // Pointer to our parser if we're currently in the process of being
+ // parsed into.
+ nsCOMPtr<nsIParser> mParser;
+
+ nsrefcnt mStackRefCnt;
+
+ // Weak reference to our sink for in case we no longer have a parser. This
+ // will allow us to flush out any pending stuff from the sink even if
+ // EndLoad() has already happened.
+ nsWeakPtr mWeakSink;
+
+ // Our update nesting level
+ uint32_t mUpdateNestLevel;
+
// Restyle root for servo's style system.
//
// We store this as an nsINode, rather than as an Element, so that we can store
// the Document node as the restyle root if the entire document (along with all
// document-level native-anonymous content) needs to be restyled.
//
// We also track which "descendant" bits (normal/animation-only/lazy-fc) the
// root corresponds to.