Bug 1543315 - part 9: Mark nsIPresShell::FlushPendingNotifications() as MOZ_CAN_RUN_SCRIPT r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Sat, 13 Apr 2019 12:43:57 +0000
changeset 528229 a57a60c0278de19bc4ab10d6f857b160cc6d74ff
parent 528228 a25a14f7150dfbd6cc3519669c85b5b1c8183059
child 528230 7ba85ea07d28cc509acb7a43a66be354febd2837
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1543315
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1543315 - part 9: Mark nsIPresShell::FlushPendingNotifications() as MOZ_CAN_RUN_SCRIPT r=smaug So, this patch makes all caller of it safe including its arguments unless they come from other methods. Differential Revision: https://phabricator.services.mozilla.com/D27225
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsIContentViewer.idl
dom/base/Document.h
dom/base/Selection.cpp
dom/base/Selection.h
dom/base/nsCopySupport.cpp
dom/base/nsCopySupport.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsFrameLoader.h
dom/canvas/CanvasRenderingContext2D.h
dom/events/Event.h
dom/events/EventStateManager.cpp
dom/events/EventStateManager.h
dom/interfaces/base/nsIDOMWindowUtils.idl
editor/libeditor/EditorBase.cpp
editor/libeditor/EditorBase.h
editor/libeditor/HTMLTableEditor.cpp
editor/libeditor/SplitNodeTransaction.cpp
editor/libeditor/TextEditor.cpp
layout/base/PresShell.cpp
layout/base/PresShell.h
layout/base/nsDocumentViewer.cpp
layout/base/nsIPresShell.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsRefreshDriver.cpp
layout/forms/nsComboboxControlFrame.cpp
layout/generic/nsFlexContainerFrame.h
layout/generic/nsFrameSelection.h
layout/generic/nsGridContainerFrame.cpp
layout/generic/nsGridContainerFrame.h
layout/generic/nsSubDocumentFrame.cpp
layout/printing/nsPrintJob.cpp
layout/printing/nsPrintJob.h
layout/svg/SVGTextFrame.cpp
layout/svg/SVGTextFrame.h
layout/xul/BoxObject.cpp
layout/xul/BoxObject.h
layout/xul/nsXULPopupManager.cpp
layout/xul/nsXULPopupManager.h
layout/xul/tree/nsTreeBodyFrame.h
toolkit/components/typeaheadfind/nsTypeAheadFind.cpp
toolkit/components/typeaheadfind/nsTypeAheadFind.h
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -6573,17 +6573,18 @@ nsresult nsDocShell::EndPageLoad(nsIWebP
   // during this load handler.
   //
   nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
 
   // Notify the ContentViewer that the Document has finished loading.  This
   // will cause any OnLoad(...) and PopState(...) handlers to fire.
   if (!mEODForCurrentDocument && mContentViewer) {
     mIsExecutingOnLoadHandler = true;
-    mContentViewer->LoadComplete(aStatus);
+    nsCOMPtr<nsIContentViewer> contentViewer = mContentViewer;
+    contentViewer->LoadComplete(aStatus);
     mIsExecutingOnLoadHandler = false;
 
     mEODForCurrentDocument = true;
 
     // If all documents have completed their loading
     // favor native event dispatch priorities
     // over performance
     if (--gNumberOfDocumentsLoading == 0) {
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -585,16 +585,17 @@ class nsDocShell final : public nsDocLoa
   bool OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
                 nsIPrincipal* aTriggeringPrincipal,
                 nsIPrincipal* aPrincipalToInherit, uint32_t aLoadType,
                 nsIContentSecurityPolicy* aCsp, bool aFireOnLocationChange,
                 bool aAddToGlobalHistory, bool aCloneSHChildren);
 
   // Helper method that is called when a new document (including any
   // sub-documents - ie. frames) has been completely loaded.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   nsresult EndPageLoad(nsIWebProgress* aProgress, nsIChannel* aChannel,
                        nsresult aResult);
 
   // Builds an error page URI (e.g. about:neterror?etc) for the given aURI
   // and displays it via the LoadErrorPage() overload below.
   nsresult LoadErrorPage(nsIURI* aURI, const char16_t* aURL,
                          const char* aErrorPage, const char* aErrorType,
                          const char16_t* aDescription, const char* aCSSClass,
--- a/docshell/base/nsIContentViewer.idl
+++ b/docshell/base/nsIContentViewer.idl
@@ -37,17 +37,17 @@ class Encoding;
 interface nsIContentViewer : nsISupports
 {
   [noscript] void init(in nsIWidgetPtr aParentWidget,
                        [const] in nsIntRectRef aBounds);
 
   attribute nsIDocShell container;
 
   [noscript,notxpcom,nostdcall] void loadStart(in Document aDoc);
-  void loadComplete(in nsresult aStatus);
+  [can_run_script] void loadComplete(in nsresult aStatus);
   [notxpcom,nostdcall] readonly attribute boolean loadCompleted;
 
   [notxpcom,nostdcall] readonly attribute boolean isStopped;
 
   /**
    * aPermitUnloadFlags are passed to PermitUnload to indicate what action to take
    * if a beforeunload handler wants to prompt the user.  It is also used by
    * permitUnloadInternal to ensure we only prompt once.
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -2052,16 +2052,17 @@ class Document : public nsINode,
   void FlushPendingNotifications(FlushType aType);
 
   /**
    * Another variant of the above FlushPendingNotifications.  This function
    * takes a ChangesToFlush to specify whether throttled animations are flushed
    * or not.
    * If in doublt, use the above FlushPendingNotifications.
    */
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   void FlushPendingNotifications(ChangesToFlush aFlush);
 
   /**
    * 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.
    */
--- a/dom/base/Selection.cpp
+++ b/dom/base/Selection.cpp
@@ -526,18 +526,17 @@ nsresult Selection::GetTableCellLocation
   // Get the child content (the cell) pointed to by starting node of range
   // We do minimal checking since GetTableSelectionType assures
   // us that this really is a table cell
   nsCOMPtr<nsIContent> child = aRange->GetChildAtStartOffset();
   if (!child) return NS_ERROR_FAILURE;
 
   // GetCellLayout depends on current frame, we need flush frame to get
   // nsITableCellLayout
-  RefPtr<PresShell> presShell = mFrameSelection->GetPresShell();
-  if (presShell) {
+  if (RefPtr<PresShell> presShell = mFrameSelection->GetPresShell()) {
     presShell->FlushPendingNotifications(FlushType::Frames);
 
     // Since calling FlushPendingNotifications, so check whether disconnected.
     if (!mFrameSelection || !mFrameSelection->GetPresShell()) {
       return NS_ERROR_FAILURE;
     }
   }
 
--- a/dom/base/Selection.h
+++ b/dom/base/Selection.h
@@ -705,16 +705,17 @@ class Selection final : public nsSupport
 
   /**
    * Test whether the supplied range points to a single table element.
    * Result is one of the TableSelection constants. "None" means
    * a table element isn't selected.
    */
   nsresult GetTableSelectionType(nsRange* aRange,
                                  TableSelection* aTableSelectionType);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   nsresult GetTableCellLocationFromRange(nsRange* aRange,
                                          TableSelection* aSelectionType,
                                          int32_t* aRow, int32_t* aCol);
   nsresult AddTableCellRange(nsRange* aRange, bool* aDidAddRange,
                              int32_t* aOutIndex);
 
   nsresult FindInsertionPoint(nsTArray<RangeData>* aElementArray,
                               nsINode* aPointNode, int32_t aPointOffset,
--- a/dom/base/nsCopySupport.cpp
+++ b/dom/base/nsCopySupport.cpp
@@ -649,34 +649,36 @@ static Element* GetElementOrNearestFlatt
       return content->AsElement();
     }
   }
   return nullptr;
 }
 
 bool nsCopySupport::FireClipboardEvent(EventMessage aEventMessage,
                                        int32_t aClipboardType,
-                                       nsIPresShell* aPresShell,
+                                       PresShell* aPresShell,
                                        Selection* aSelection,
                                        bool* aActionTaken) {
   if (aActionTaken) {
     *aActionTaken = false;
   }
 
   EventMessage originalEventMessage = aEventMessage;
   if (originalEventMessage == ePasteNoFormatting) {
     originalEventMessage = ePaste;
   }
 
   NS_ASSERTION(originalEventMessage == eCut || originalEventMessage == eCopy ||
                    originalEventMessage == ePaste,
                "Invalid clipboard event type");
 
-  nsCOMPtr<nsIPresShell> presShell = aPresShell;
-  if (!presShell) return false;
+  RefPtr<PresShell> presShell = aPresShell;
+  if (!presShell) {
+    return false;
+  }
 
   nsCOMPtr<Document> doc = presShell->GetDocument();
   if (!doc) return false;
 
   nsCOMPtr<nsPIDOMWindowOuter> piWindow = doc->GetWindow();
   if (!piWindow) return false;
 
   // Event target of clipboard events should be an element node which
@@ -759,17 +761,19 @@ bool nsCopySupport::FireClipboardEvent(E
       *aActionTaken = true;
     }
     return doDefault;
   }
 
   // Update the presentation in case the event handler modified the selection,
   // see bug 602231.
   presShell->FlushPendingNotifications(FlushType::Frames);
-  if (presShell->IsDestroying()) return false;
+  if (presShell->IsDestroying()) {
+    return false;
+  }
 
   // if the event was not cancelled, do the default copy. If the event was
   // cancelled, use the data added to the data transfer and copy that instead.
   uint32_t count = 0;
   if (doDefault) {
     // find the focused node
     nsIContent* sourceContent = targetElement.get();
     if (targetElement->IsInNativeAnonymousSubtree()) {
--- a/dom/base/nsCopySupport.h
+++ b/dom/base/nsCopySupport.h
@@ -10,20 +10,20 @@
 #include "mozilla/dom/Document.h"
 #include "nsStringFwd.h"
 #include "mozilla/EventForwards.h"
 
 class nsINode;
 class nsIImageLoadingContent;
 class nsIContent;
 class nsITransferable;
-class nsIPresShell;
 class nsILoadContext;
 
 namespace mozilla {
+class PresShell;
 namespace dom {
 class Document;
 class Selection;
 }  // namespace dom
 }  // namespace mozilla
 
 class nsCopySupport {
   // class of static helper functions for copy support
@@ -90,16 +90,17 @@ class nsCopySupport {
    *
    * aClipboardType specifies which clipboard to use, from nsIClipboard.
    *
    * If aActionTaken is non-NULL, it will be set to true if an action was
    * taken, whether it be the default action or the default being prevented.
    *
    * If the event is cancelled or an error occurs, false will be returned.
    */
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   static bool FireClipboardEvent(mozilla::EventMessage aEventMessage,
                                  int32_t aClipboardType,
-                                 nsIPresShell* aPresShell,
+                                 mozilla::PresShell* aPresShell,
                                  mozilla::dom::Selection* aSelection,
                                  bool* aActionTaken = nullptr);
 };
 
 #endif
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -366,17 +366,17 @@ nsDOMWindowUtils::Redraw(uint32_t aCount
       return NS_OK;
     }
   }
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::UpdateLayerTree() {
-  if (PresShell* presShell = GetPresShell()) {
+  if (RefPtr<PresShell> presShell = GetPresShell()) {
     // Don't flush throttled animations since it might fire MozAfterPaint event
     // (in WebRender it constantly does), thus the reftest harness can't take
     // any snapshot until the throttled animations finished.
     presShell->FlushPendingNotifications(
         ChangesToFlush(FlushType::Display, false /* flush animations */));
     RefPtr<nsViewManager> vm = presShell->GetViewManager();
     nsView* view = vm->GetRootView();
     if (view) {
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -246,17 +246,17 @@ class nsFrameLoader final : public nsStu
    * the frame is being torn down; this notifies us that out widget and view
    * are going away and we should unhook from them.
    */
   void Hide();
 
   // Used when content is causing a FrameLoader to be created, and
   // needs to try forcing layout to flush in order to get accurate
   // dimensions for the content area.
-  void ForceLayoutIfNecessary();
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY void ForceLayoutIfNecessary();
 
   // The guts of an nsFrameLoaderOwner::SwapFrameLoader implementation.  A
   // frame loader owner needs to call this, and pass in the two references to
   // nsRefPtrs for frame loaders that need to be swapped.
   nsresult SwapWithOtherLoader(nsFrameLoader* aOther,
                                nsFrameLoaderOwner* aThisOwner,
                                nsFrameLoaderOwner* aOtherOwner);
 
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -502,17 +502,17 @@ class CanvasRenderingContext2D final : p
 
   void OnShutdown();
 
   /**
    * Update CurrentState().filter with the filter description for
    * CurrentState().filterChain.
    * Flushes the PresShell, so the world can change if you call this function.
    */
-  void UpdateFilter();
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY void UpdateFilter();
 
  protected:
   nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
                              uint32_t aWidth, uint32_t aHeight,
                              nsIPrincipal& aSubjectPrincipal,
                              JSObject** aRetval);
 
   nsresult PutImageData_explicit(int32_t aX, int32_t aY, uint32_t aW,
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -149,16 +149,17 @@ class Event : public nsISupports, public
                                      CSSIntPoint aDefaultPoint);
   static CSSIntPoint GetPageCoords(nsPresContext* aPresContext,
                                    WidgetEvent* aEvent,
                                    LayoutDeviceIntPoint aPoint,
                                    CSSIntPoint aDefaultPoint);
   static CSSIntPoint GetScreenCoords(nsPresContext* aPresContext,
                                      WidgetEvent* aEvent,
                                      LayoutDeviceIntPoint aPoint);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   static CSSIntPoint GetOffsetCoords(nsPresContext* aPresContext,
                                      WidgetEvent* aEvent,
                                      LayoutDeviceIntPoint aPoint,
                                      CSSIntPoint aDefaultPoint);
 
   static already_AddRefed<Event> Constructor(EventTarget* aEventTarget,
                                              const nsAString& aType,
                                              const EventInit& aParam);
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -5047,17 +5047,18 @@ nsresult EventStateManager::HandleMiddle
       return NS_ERROR_FAILURE;
     }
   }
 
   // Move selection to the clicked point.
   nsCOMPtr<nsIContent> container;
   int32_t offset;
   nsLayoutUtils::GetContainerAndOffsetAtEvent(
-      aPresShell, aMouseEvent, getter_AddRefs(container), &offset);
+      static_cast<PresShell*>(aPresShell), aMouseEvent,
+      getter_AddRefs(container), &offset);
   if (container) {
     // XXX If readonly or disabled <input> or <textarea> in contenteditable
     //     designMode editor is clicked, the point is in the editor.
     //     However, outer HTMLEditor and Selection should handle it.
     //     So, in such case, Selection::Collapse() will fail.
     DebugOnly<nsresult> rv = selection->Collapse(container, offset);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "Failed to collapse Selection at middle clicked");
@@ -5073,17 +5074,18 @@ nsresult EventStateManager::HandleMiddle
     if (NS_SUCCEEDED(rv) && selectionSupported) {
       clipboardType = nsIClipboard::kSelectionClipboard;
     }
   }
 
   // Fire ePaste event by ourselves since we need to dispatch "paste" event
   // even if the middle click event was consumed for compatibility with
   // Chromium.
-  if (!nsCopySupport::FireClipboardEvent(ePaste, clipboardType, aPresShell,
+  if (!nsCopySupport::FireClipboardEvent(ePaste, clipboardType,
+                                         static_cast<PresShell*>(aPresShell),
                                          selection)) {
     *aStatus = nsEventStatus_eConsumeNoDefault;
     return NS_OK;
   }
 
   // Although we've fired "paste" event, there is no editor to accept the
   // clipboard content.
   if (!aTextEditor) {
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -547,16 +547,17 @@ class EventStateManager : public nsSuppo
   MOZ_CAN_RUN_SCRIPT
   nsresult DispatchClickEvents(nsIPresShell* aPresShell,
                                WidgetMouseEvent* aMouseUpEvent,
                                nsEventStatus* aStatus,
                                nsIContent* aMouseUpContent,
                                nsIContent* aOverrideClickTarget);
 
   void EnsureDocument(nsPresContext* aPresContext);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   void FlushPendingEvents(nsPresContext* aPresContext);
 
   /**
    * The phases of WalkESMTreeToHandleAccessKey processing. See below.
    */
   typedef enum {
     eAccessKeyProcessingNormal = 0,
     eAccessKeyProcessingUp,
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -101,16 +101,17 @@ interface nsIDOMWindowUtils : nsISupport
    * in milliseconds, that the redraws took.  If aCount is not specified
    * or is 0, it is taken to be 1.
    */
   unsigned long redraw([optional] in unsigned long aCount);
 
   /**
    * Force a synchronous layer transaction for this window if necessary.
    */
+  [can_run_script]
   void updateLayerTree();
 
   /**
    * Get the last used layer transaction id for this window's refresh driver.
    */
   readonly attribute unsigned long long lastTransactionId;
 
   /**
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -2933,18 +2933,17 @@ void EditorBase::DoSplitNode(const Edito
     }
   }
 
   // XXX Why do we ignore an error while moving nodes from the right node to
   //     the left node?
   aError.SuppressException();
 
   // Handle selection
-  RefPtr<PresShell> presShell = GetPresShell();
-  if (presShell) {
+  if (RefPtr<PresShell> presShell = GetPresShell()) {
     presShell->FlushPendingNotifications(FlushType::Frames);
   }
   NS_WARNING_ASSERTION(!Destroyed(),
                        "The editor is destroyed during splitting a node");
 
   bool allowedTransactionsToChangeSelection =
       AllowsTransactionsToChangeSelection();
 
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -1343,16 +1343,17 @@ class EditorBase : public nsIEditor,
    *                            previous sibling.
    * @param aError              Must have not already failed.
    *                            If succeed to insert aLeftNode before the
    *                            right node and remove unnecessary contents
    *                            (and collapse selection at end of the left
    *                            node if necessary), returns no error.
    *                            Otherwise, an error.
    */
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   void DoSplitNode(const EditorDOMPoint& aStartOfRightNode,
                    nsIContent& aNewLeftNode, ErrorResult& aError);
 
   /**
    * DoJoinNodes() merges contents in aNodeToJoin to aNodeToKeep and remove
    * aNodeToJoin from the DOM tree.  aNodeToJoin and aNodeToKeep must have
    * same parent, aParent.  Additionally, if one of aNodeToJoin or aNodeToKeep
    * is a text node, the other must be a text node.
--- a/editor/libeditor/HTMLTableEditor.cpp
+++ b/editor/libeditor/HTMLTableEditor.cpp
@@ -769,18 +769,17 @@ nsresult HTMLEditor::InsertTableRowsWith
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   // SetSelectionAfterTableEdit from AutoSelectionSetterAfterTableEdit will
   // access frame selection, so we need reframe.
   // Because GetTableCellElementAt() depends on frame.
-  RefPtr<PresShell> presShell = GetPresShell();
-  if (presShell) {
+  if (RefPtr<PresShell> presShell = GetPresShell()) {
     presShell->FlushPendingNotifications(FlushType::Frames);
   }
 
   return NS_OK;
 }
 
 nsresult HTMLEditor::DeleteTableElementAndChildrenWithTransaction(
     Element& aTableElement) {
--- a/editor/libeditor/SplitNodeTransaction.cpp
+++ b/editor/libeditor/SplitNodeTransaction.cpp
@@ -75,31 +75,33 @@ SplitNodeTransaction::DoTransaction() {
 
   // Get the parent node
   mParent = mStartOfRightNode.GetContainer()->GetParentNode();
   if (NS_WARN_IF(!mParent)) {
     return NS_ERROR_FAILURE;
   }
 
   // Insert the new node
-  mEditorBase->DoSplitNode(EditorDOMPoint(mStartOfRightNode), *mNewLeftNode,
-                           error);
+  RefPtr<EditorBase> editorBase = mEditorBase;
+  nsCOMPtr<nsIContent> newLeftNode = mNewLeftNode;
+  editorBase->DoSplitNode(EditorDOMPoint(mStartOfRightNode), *newLeftNode,
+                          error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
-  if (!mEditorBase->AllowsTransactionsToChangeSelection()) {
+  if (!editorBase->AllowsTransactionsToChangeSelection()) {
     return NS_OK;
   }
 
   NS_WARNING_ASSERTION(
-      !mEditorBase->Destroyed(),
+      !editorBase->Destroyed(),
       "The editor has gone but SplitNodeTransaction keeps trying to modify "
       "Selection");
-  RefPtr<Selection> selection = mEditorBase->GetSelection();
+  RefPtr<Selection> selection = editorBase->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
   }
   if (NS_WARN_IF(error.Failed())) {
     // XXX This must be a bug.
     error.SuppressException();
   }
   EditorRawDOMPoint atEndOfLeftNode;
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -1756,19 +1756,19 @@ bool TextEditor::FireClipboardEvent(Even
     CommitComposition();
   }
 
   RefPtr<PresShell> presShell = GetPresShell();
   if (NS_WARN_IF(!presShell)) {
     return false;
   }
 
-  if (!nsCopySupport::FireClipboardEvent(aEventMessage, aSelectionType,
-                                         presShell, SelectionRefPtr(),
-                                         aActionTaken)) {
+  if (!nsCopySupport::FireClipboardEvent(
+          aEventMessage, aSelectionType, presShell,
+          MOZ_KnownLive(SelectionRefPtr()), aActionTaken)) {
     return false;
   }
 
   // If the event handler caused the editor to be destroyed, return false.
   // Otherwise return true to indicate that the event was not cancelled.
   return !mDidPreDestroy;
 }
 
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -473,17 +473,17 @@ class MOZ_STACK_CLASS nsPresShellEventCB
     if (aVisitor.mPresContext && aVisitor.mEvent->mClass != eBasicEventClass) {
       if (aVisitor.mEvent->mMessage == eMouseDown ||
           aVisitor.mEvent->mMessage == eMouseUp) {
         // Mouse-up and mouse-down events call nsFrame::HandlePress/Release
         // which call GetContentOffsetsFromPoint which requires up-to-date
         // layout. Bring layout up-to-date now so that GetCurrentEventFrame()
         // below will return a real frame and we don't have to worry about
         // destroying it by flushing later.
-        mPresShell->FlushPendingNotifications(FlushType::Layout);
+        MOZ_KnownLive(mPresShell)->FlushPendingNotifications(FlushType::Layout);
       } else if (aVisitor.mEvent->mMessage == eWheel &&
                  aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
         nsIFrame* frame = mPresShell->GetCurrentEventFrame();
         if (frame) {
           // chrome (including addons) should be able to know if content
           // handles both D3E "wheel" event and legacy mouse scroll events.
           // We should dispatch legacy mouse events before dispatching the
           // "wheel" event into system group.
@@ -6732,17 +6732,17 @@ bool PresShell::EventHandler::MaybeFlush
     case eMouseUp: {
       RefPtr<nsPresContext> presContext = mPresShell->GetPresContext();
       if (NS_WARN_IF(!presContext)) {
         return false;
       }
       uint64_t framesConstructedCount = presContext->FramesConstructedCount();
       uint64_t framesReflowedCount = presContext->FramesReflowedCount();
 
-      mPresShell->FlushPendingNotifications(FlushType::Layout);
+      MOZ_KnownLive(mPresShell)->FlushPendingNotifications(FlushType::Layout);
       return framesConstructedCount != presContext->FramesConstructedCount() ||
              framesReflowedCount != presContext->FramesReflowedCount();
     }
     default:
       return false;
   }
 }
 
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -99,18 +99,19 @@ class PresShell final : public nsIPresSh
   MOZ_CAN_RUN_SCRIPT nsresult ResizeReflow(
       nscoord aWidth, nscoord aHeight, nscoord aOldWidth = 0,
       nscoord aOldHeight = 0,
       ResizeReflowOptions aOptions = ResizeReflowOptions::eBSizeExact) override;
   MOZ_CAN_RUN_SCRIPT nsresult ResizeReflowIgnoreOverride(
       nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight,
       ResizeReflowOptions aOptions = ResizeReflowOptions::eBSizeExact) override;
 
+  MOZ_CAN_RUN_SCRIPT
   void DoFlushPendingNotifications(FlushType aType) override;
-  MOZ_CAN_RUN_SCRIPT_BOUNDARY
+  MOZ_CAN_RUN_SCRIPT
   void DoFlushPendingNotifications(ChangesToFlush aType) override;
 
   nsRectVisibility GetRectVisibility(nsIFrame* aFrame, const nsRect& aRect,
                                      nscoord aMinTwips) const override;
 
   nsresult CaptureHistoryState(
       nsILayoutHistoryState** aLayoutHistoryState) override;
 
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2511,18 +2511,19 @@ NS_IMETHODIMP nsDocumentViewer::SelectAl
   }
 
   mozilla::dom::Selection::AutoUserInitiated userSelection(selection);
   selection->SelectAllChildren(*bodyNode, err);
   return err.StealNSResult();
 }
 
 NS_IMETHODIMP nsDocumentViewer::CopySelection() {
+  RefPtr<PresShell> presShell = mPresShell;
   nsCopySupport::FireClipboardEvent(eCopy, nsIClipboard::kGlobalClipboard,
-                                    mPresShell, nullptr);
+                                    presShell, nullptr);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDocumentViewer::CopyLinkLocation() {
   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
   nsCOMPtr<nsINode> node = GetPopupLinkNode();
   // make noise if we're not in a link
   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -550,38 +550,41 @@ class nsIPresShell : public nsStubDocume
    * This method can execute script, which can destroy this presshell object
    * unless someone is holding a reference to it on the stack.  The presshell
    * itself will ensure it lives up until the method returns, but callers who
    * plan to use the presshell after this call should hold a strong ref
    * themselves!
    *
    * @param aType the type of notifications to flush
    */
+  MOZ_CAN_RUN_SCRIPT
   void FlushPendingNotifications(mozilla::FlushType aType) {
     if (!NeedFlush(aType)) {
       return;
     }
 
     DoFlushPendingNotifications(aType);
   }
 
+  MOZ_CAN_RUN_SCRIPT
   void FlushPendingNotifications(mozilla::ChangesToFlush aType) {
     if (!NeedFlush(aType.mFlushType)) {
       return;
     }
 
     DoFlushPendingNotifications(aType);
   }
 
  protected:
   /**
    * Implementation methods for FlushPendingNotifications.
    */
+  MOZ_CAN_RUN_SCRIPT
   virtual void DoFlushPendingNotifications(mozilla::FlushType aType) = 0;
-  MOZ_CAN_RUN_SCRIPT_BOUNDARY
+  MOZ_CAN_RUN_SCRIPT
   virtual void DoFlushPendingNotifications(mozilla::ChangesToFlush aType) = 0;
 
  public:
   /**
    * Whether we might need a flush for the given flush type.  If this
    * function returns false, we definitely don't need to flush.
    *
    * @param aFlushType The flush type to check.  This must be
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2265,17 +2265,17 @@ nsIFrame* nsLayoutUtils::GetPopupFrameFo
             GetEventCoordinatesRelativeTo(aEvent, popup))) {
       return popup;
     }
   }
 #endif
   return nullptr;
 }
 
-void nsLayoutUtils::GetContainerAndOffsetAtEvent(nsIPresShell* aPresShell,
+void nsLayoutUtils::GetContainerAndOffsetAtEvent(PresShell* aPresShell,
                                                  const WidgetEvent* aEvent,
                                                  nsIContent** aContainer,
                                                  int32_t* aOffset) {
   MOZ_ASSERT(aContainer || aOffset);
 
   if (aContainer) {
     *aContainer = nullptr;
   }
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -57,16 +57,17 @@ class nsIFrame;
 class nsStyleCoord;
 class nsPIDOMWindowOuter;
 class imgIRequest;
 struct nsStyleFont;
 struct nsOverflowAreas;
 
 namespace mozilla {
 class ComputedStyle;
+class PresShell;
 enum class PseudoStyleType : uint8_t;
 class EventListenerManager;
 enum class LayoutFrameType : uint8_t;
 struct IntrinsicSize;
 struct ContainerLayerParameters;
 class WritingMode;
 class DisplayItemClip;
 class EffectSet;
@@ -791,17 +792,17 @@ class nsLayoutUtils {
    * @param aEvent          The event having coordinates where you want to
    *                        collapse Selection.
    * @param aContainer      Returns the container node at the point.
    *                        Set nullptr if you don't need this.
    * @param aOffset         Returns offset in the container node at the point.
    *                        Set nullptr if you don't need this.
    */
   MOZ_CAN_RUN_SCRIPT
-  static void GetContainerAndOffsetAtEvent(nsIPresShell* aPresShell,
+  static void GetContainerAndOffsetAtEvent(mozilla::PresShell* aPresShell,
                                            const mozilla::WidgetEvent* aEvent,
                                            nsIContent** aContainer,
                                            int32_t* aOffset);
 
   /**
    * Translate from widget coordinates to the view's coordinates
    * @param aPresContext the PresContext for the view
    * @param aWidget the widget
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1900,51 +1900,53 @@ void nsRefreshDriver::Tick(VsyncId aId, 
 
       if (mPresContext && mPresContext->GetPresShell()) {
         AutoTArray<nsIPresShell*, 16> observers;
         observers.AppendElements(mStyleFlushObservers);
         for (uint32_t j = observers.Length();
              j && mPresContext && mPresContext->GetPresShell(); --j) {
           // Make sure to not process observers which might have been removed
           // during previous iterations.
-          nsIPresShell* shell = observers[j - 1];
-          if (!mStyleFlushObservers.RemoveElement(shell)) continue;
-
-          nsCOMPtr<nsIPresShell> shellKungFuDeathGrip(shell);
-          shell->mObservingStyleFlushes = false;
-          shell->FlushPendingNotifications(
+          nsIPresShell* rawPresShell = observers[j - 1];
+          if (!mStyleFlushObservers.RemoveElement(rawPresShell)) {
+            continue;
+          }
+          RefPtr<PresShell> presShell = static_cast<PresShell*>(rawPresShell);
+          presShell->mObservingStyleFlushes = false;
+          presShell->FlushPendingNotifications(
               ChangesToFlush(FlushType::Style, false));
           // Inform the FontFaceSet that we ticked, so that it can resolve its
           // ready promise if it needs to (though it might still be waiting on
           // a layout flush).
-          shell->NotifyFontFaceSetOnRefresh();
+          presShell->NotifyFontFaceSetOnRefresh();
           mNeedToRecomputeVisibility = true;
         }
       }
     } else if (i == 2) {
       // This is the FlushType::Layout case.
       AutoTArray<nsIPresShell*, 16> observers;
       observers.AppendElements(mLayoutFlushObservers);
       for (uint32_t j = observers.Length();
            j && mPresContext && mPresContext->GetPresShell(); --j) {
         // Make sure to not process observers which might have been removed
         // during previous iterations.
-        nsIPresShell* shell = observers[j - 1];
-        if (!mLayoutFlushObservers.RemoveElement(shell)) continue;
-
-        nsCOMPtr<nsIPresShell> shellKungFuDeathGrip(shell);
-        shell->mObservingLayoutFlushes = false;
-        shell->mWasLastReflowInterrupted = false;
-        FlushType flushType = HasPendingAnimations(shell)
+        nsIPresShell* rawPresShell = observers[j - 1];
+        if (!mLayoutFlushObservers.RemoveElement(rawPresShell)) {
+          continue;
+        }
+        RefPtr<PresShell> presShell = static_cast<PresShell*>(rawPresShell);
+        presShell->mObservingLayoutFlushes = false;
+        presShell->mWasLastReflowInterrupted = false;
+        FlushType flushType = HasPendingAnimations(presShell)
                                   ? FlushType::Layout
                                   : FlushType::InterruptibleLayout;
-        shell->FlushPendingNotifications(ChangesToFlush(flushType, false));
+        presShell->FlushPendingNotifications(ChangesToFlush(flushType, false));
         // Inform the FontFaceSet that we ticked, so that it can resolve its
         // ready promise if it needs to.
-        shell->NotifyFontFaceSetOnRefresh();
+        presShell->NotifyFontFaceSetOnRefresh();
         mNeedToRecomputeVisibility = true;
       }
     }
 
     // The pres context may be destroyed during we do the flushing.
     if (!mPresContext || !mPresContext->GetPresShell()) {
       StopTimer();
       return;
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -503,17 +503,17 @@ class nsAsyncRollup : public Runnable {
   }
   WeakFrame mFrame;
 };
 
 class nsAsyncResize : public Runnable {
  public:
   explicit nsAsyncResize(nsComboboxControlFrame* aFrame)
       : mozilla::Runnable("nsAsyncResize"), mFrame(aFrame) {}
-  NS_IMETHOD Run() override {
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
     if (mFrame.IsAlive()) {
       nsComboboxControlFrame* combo =
           static_cast<nsComboboxControlFrame*>(mFrame.GetFrame());
       static_cast<nsListControlFrame*>(combo->mDropdownFrame)
           ->SetSuppressScrollbarUpdate(true);
       RefPtr<PresShell> presShell = mFrame->PresShell();
       presShell->FrameNeedsReflow(combo->mDropdownFrame, nsIPresShell::eResize,
                                   NS_FRAME_IS_DIRTY);
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -192,16 +192,17 @@ class nsFlexContainerFrame final : publi
   }
 
   /**
    * Return aFrame as a flex frame after ensuring it has computed flex info.
    * @return nullptr if aFrame is null or doesn't have a flex frame
    *         as its content insertion frame.
    * @note this might destroy layout/style data since it may flush layout.
    */
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   static nsFlexContainerFrame* GetFlexFrameWithComputedInfo(nsIFrame* aFrame);
 
   /**
    * Given a frame for a flex item, this method returns true IFF that flex
    * item's inline axis is the same as (i.e. not orthogonal to) its flex
    * container's main axis.
    *
    * (This method is only intended to be used from external
--- a/layout/generic/nsFrameSelection.h
+++ b/layout/generic/nsFrameSelection.h
@@ -510,17 +510,17 @@ class nsFrameSelection final {
   /**
    * PhysicalMove will generally be called from the nsiselectioncontroller
    * implementations. the effect being the selection will move one unit
    * 'aAmount' in the given aDirection.
    * @param aDirection  the direction to move the selection
    * @param aAmount     amount of movement (char/line; word/page; eol/doc)
    * @param aExtend     continue selection
    */
-  /*unsafe*/
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   nsresult PhysicalMove(int16_t aDirection, int16_t aAmount, bool aExtend);
 
   /**
    * CharacterMove will generally be called from the nsiselectioncontroller
    * implementations. the effect being the selection will move one character
    * left or right.
    * @param aForward move forward in document.
    * @param aExtend continue selection
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -6738,17 +6738,17 @@ nsGridContainerFrame* nsGridContainerFra
                          !gridFrame->HasProperty(GridColumnLineInfo()) ||
                          !gridFrame->HasProperty(GridRowLineInfo()));
 
     if (reflowNeeded) {
       // Trigger a reflow that generates additional grid property data.
       // Hold onto aFrame while we do this, in case reflow destroys it.
       AutoWeakFrame weakFrameRef(aFrame);
 
-      mozilla::PresShell* presShell = gridFrame->PresShell();
+      RefPtr<mozilla::PresShell> presShell = gridFrame->PresShell();
       gridFrame->AddStateBits(NS_STATE_GRID_GENERATE_COMPUTED_VALUES);
       presShell->FrameNeedsReflow(gridFrame, nsIPresShell::eResize,
                                   NS_FRAME_IS_DIRTY);
       presShell->FlushPendingNotifications(FlushType::Layout);
 
       // Since the reflow may have side effects, get the grid frame
       // again. But if the weakFrameRef is no longer valid, then we
       // must bail out.
--- a/layout/generic/nsGridContainerFrame.h
+++ b/layout/generic/nsGridContainerFrame.h
@@ -235,16 +235,17 @@ class nsGridContainerFrame final : publi
    */
   static nsGridContainerFrame* GetGridContainerFrame(nsIFrame* aFrame);
 
   /**
    * Return a container grid frame, and ensure it has computed grid info
    * @return nullptr if aFrame has no grid container, or frame was destroyed
    * @note this might destroy layout/style data since it may flush layout
    */
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   static nsGridContainerFrame* GetGridFrameWithComputedInfo(nsIFrame* aFrame);
 
   struct TrackSize;
   struct GridItemInfo;
   struct GridReflowInput;
   struct FindItemInGridOrderResult {
     // The first(last) item in (reverse) grid order.
     const GridItemInfo* mItem;
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -899,31 +899,31 @@ class nsHideViewer : public Runnable {
         mFrameLoader(aFrameLoader),
         mPresShell(aPresShell),
         mHideViewerIfFrameless(aHideViewerIfFrameless) {
     NS_ASSERTION(mFrameElement, "Must have a frame element");
     NS_ASSERTION(mFrameLoader, "Must have a frame loader");
     NS_ASSERTION(mPresShell, "Must have a presshell");
   }
 
-  NS_IMETHOD Run() override {
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
     // Flush frames, to ensure any pending display:none changes are made.
     // Note it can be unsafe to flush if we've destroyed the presentation
     // for some other reason, like if we're shutting down.
     //
     // But avoid the flush if we know for sure we're away, like when we're out
     // of the document already.
     //
     // FIXME(emilio): This could still be a perf footgun when removing lots of
     // siblings where each of them cause the reframe of an ancestor which happen
     // to contain a subdocument.
     //
     // We should find some way to avoid that!
     if (!mPresShell->IsDestroying() && mFrameElement->IsInComposedDoc()) {
-      mPresShell->FlushPendingNotifications(FlushType::Frames);
+      MOZ_KnownLive(mPresShell)->FlushPendingNotifications(FlushType::Frames);
     }
 
     // Either the frame has been constructed by now, or it never will be,
     // either way we want to clear the stashed views.
     mFrameLoader->SetDetachedSubdocFrame(nullptr, nullptr);
 
     nsSubDocumentFrame* frame = do_QueryFrame(mFrameElement->GetPrimaryFrame());
     if ((!frame && mHideViewerIfFrameless) || mPresShell->IsDestroying()) {
--- a/layout/printing/nsPrintJob.cpp
+++ b/layout/printing/nsPrintJob.cpp
@@ -1637,17 +1637,18 @@ nsresult nsPrintJob::ReconstructAndReflo
 
       MOZ_ASSERT(!documentIsTopLevel, "How could this happen?");
 
       if (NS_FAILED(rv) || doReturn) {
         return rv;
       }
     }
 
-    po->mPresShell->FlushPendingNotifications(FlushType::Layout);
+    RefPtr<PresShell> presShell = static_cast<PresShell*>(po->mPresShell.get());
+    presShell->FlushPendingNotifications(FlushType::Layout);
 
     // If the printing was canceled or restarted with different data,
     // let's stop doing this printing.
     if (NS_WARN_IF(mPrt != printData)) {
       return NS_ERROR_FAILURE;
     }
 
     nsresult rv = UpdateSelectionAndShrinkPrintObject(po, documentIsTopLevel);
@@ -2285,17 +2286,18 @@ nsresult nsPrintJob::ReflowPrintObject(c
   }
 
   rv = aPO->mPresShell->Initialize();
 
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ASSERTION(aPO->mPresShell, "Presshell should still be here");
 
   // Process the reflow event Initialize posted
-  aPO->mPresShell->FlushPendingNotifications(FlushType::Layout);
+  RefPtr<PresShell> presShell = static_cast<PresShell*>(aPO->mPresShell.get());
+  presShell->FlushPendingNotifications(FlushType::Layout);
 
   rv = UpdateSelectionAndShrinkPrintObject(aPO.get(), documentIsTopLevel);
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef EXTENDED_DEBUG_PRINTING
   if (MOZ_LOG_TEST(gPrintingLog, DUMP_LAYOUT_LEVEL)) {
     nsAutoCString docStr;
     nsAutoCString urlStr;
--- a/layout/printing/nsPrintJob.h
+++ b/layout/printing/nsPrintJob.h
@@ -116,16 +116,17 @@ class nsPrintJob final : public nsIObser
 
   //---------------------------------------------------------------------
   void BuildDocTree(nsIDocShell* aParentNode,
                     nsTArray<nsPrintObject*>* aDocList,
                     const mozilla::UniquePtr<nsPrintObject>& aPO);
   nsresult ReflowDocList(const mozilla::UniquePtr<nsPrintObject>& aPO,
                          bool aSetPixelScale);
 
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   nsresult ReflowPrintObject(const mozilla::UniquePtr<nsPrintObject>& aPO);
 
   void CheckForChildFrameSets(const mozilla::UniquePtr<nsPrintObject>& aPO);
 
   void CalcNumPrintablePages(int32_t& aNumPages);
   void ShowPrintProgress(bool aIsForPrinting, bool& aDoNotify);
   nsresult CleanupOnFailure(nsresult aResult, bool aIsPrinting);
   // If FinishPrintPreview() fails, caller may need to reset the state of the
@@ -198,16 +199,17 @@ class nsPrintJob final : public nsIObser
 
   nsresult AfterNetworkPrint(bool aHandleError);
 
   nsresult SetRootView(nsPrintObject* aPO, bool& aDoReturn,
                        bool& aDocumentIsTopLevel, nsSize& aAdjSize);
   nsView* GetParentViewForRoot();
   bool DoSetPixelScale();
   void UpdateZoomRatio(nsPrintObject* aPO, bool aSetPixelScale);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   nsresult ReconstructAndReflow(bool aDoSetPixelScale);
   nsresult UpdateSelectionAndShrinkPrintObject(nsPrintObject* aPO,
                                                bool aDocumentIsTopLevel);
   nsresult InitPrintDocConstruction(bool aHandleError);
   void FirePrintPreviewUpdateEvent();
 
   void PageDone(nsresult aResult);
 
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -3851,17 +3851,18 @@ nsresult SVGTextFrame::GetSubStringLengt
                                                       uint32_t nchars,
                                                       float* aResult) {
   // We need to make sure that we've been reflowed before updating the glyph
   // positioning.
   // XXX perf: It may be possible to limit reflow to just calling ReflowSVG,
   // but we would still need to resort to full reflow for percentage
   // positioning attributes.  For now we just do a full reflow regardless since
   // the cases that would cause us to be called are relatively uncommon.
-  PresShell()->FlushPendingNotifications(FlushType::Layout);
+  RefPtr<mozilla::PresShell> presShell = PresShell();
+  presShell->FlushPendingNotifications(FlushType::Layout);
 
   UpdateGlyphPositioning();
 
   // Convert charnum/nchars from addressable characters relative to
   // aContent to global character indices.
   CharIterator chit(this, CharIterator::eAddressable, aContent);
   if (!chit.AdvanceToSubtree() || !chit.Next(charnum) ||
       chit.IsAfterSubtree()) {
--- a/layout/svg/SVGTextFrame.h
+++ b/layout/svg/SVGTextFrame.h
@@ -389,16 +389,17 @@ class SVGTextFrame final : public nsSVGD
 
   /**
    * This fallback version of GetSubStringLength that flushes layout and takes
    * into account glyph positioning.  As per the SVG 2 spec, typically glyph
    * positioning does not affect the results of getSubStringLength, but one
    * exception is text in a textPath where we need to ignore characters that
    * fall off the end of the textPath path.
    */
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   nsresult GetSubStringLengthSlowFallback(nsIContent* aContent,
                                           uint32_t charnum, uint32_t nchars,
                                           float* aResult);
 
   /**
    * Converts the specified index into mPositions to an addressable
    * character index (as can be used with the SVG DOM text methods)
    * relative to the specified text child content element.
--- a/layout/xul/BoxObject.cpp
+++ b/layout/xul/BoxObject.cpp
@@ -77,60 +77,78 @@ nsresult BoxObject::Init(Element* aEleme
 
 void BoxObject::Clear() {
   mPropertyTable = nullptr;
   mContent = nullptr;
 }
 
 void BoxObject::ClearCachedValues() {}
 
-nsIFrame* BoxObject::GetFrame(bool aFlushLayout) {
-  nsIPresShell* shell = GetPresShell(aFlushLayout);
-  if (!shell) return nullptr;
+nsIFrame* BoxObject::GetFrame() const {
+  if (!GetPresShell() || !mContent) {
+    return nullptr;
+  }
+  return mContent->GetPrimaryFrame();
+}
 
-  if (!aFlushLayout) {
-    // If we didn't flush layout when getting the presshell, we should at least
-    // flush to make sure our frame model is up to date.
-    // XXXbz should flush on document, no?  Except people call this from
-    // frame code, maybe?
-    shell->FlushPendingNotifications(FlushType::Frames);
+nsIFrame* BoxObject::GetFrameWithFlushPendingNotifications() {
+  RefPtr<PresShell> presShell = GetPresShellWithFlushPendingNotifications();
+  if (!presShell) {
+    return nullptr;
   }
 
+  // If we didn't flush layout when getting the presshell, we should at least
+  // flush to make sure our frame model is up to date.
+  // XXXbz should flush on document, no?  Except people call this from
+  // frame code, maybe?
+  presShell->FlushPendingNotifications(FlushType::Frames);
+
   // The flush might have killed mContent.
   if (!mContent) {
     return nullptr;
   }
 
   return mContent->GetPrimaryFrame();
 }
 
-nsIPresShell* BoxObject::GetPresShell(bool aFlushLayout) {
+PresShell* BoxObject::GetPresShell() const {
+  if (!mContent) {
+    return nullptr;
+  }
+
+  Document* doc = mContent->GetComposedDoc();
+  if (!doc) {
+    return nullptr;
+  }
+
+  return doc->GetPresShell();
+}
+
+PresShell* BoxObject::GetPresShellWithFlushPendingNotifications() {
   if (!mContent) {
     return nullptr;
   }
 
   RefPtr<Document> doc = mContent->GetComposedDoc();
   if (!doc) {
     return nullptr;
   }
 
-  if (aFlushLayout) {
-    doc->FlushPendingNotifications(FlushType::Layout);
-  }
+  doc->FlushPendingNotifications(FlushType::Layout);
 
   return doc->GetPresShell();
 }
 
 nsresult BoxObject::GetOffsetRect(nsIntRect& aRect) {
   aRect.SetRect(0, 0, 0, 0);
 
   if (!mContent) return NS_ERROR_NOT_INITIALIZED;
 
   // Get the Frame for our content
-  nsIFrame* frame = GetFrame(true);
+  nsIFrame* frame = GetFrameWithFlushPendingNotifications();
   if (frame) {
     // Get its origin
     nsPoint origin = frame->GetPositionIgnoringScrolling();
 
     // Find the frame parent whose content is the document element.
     Element* docElement = mContent->GetComposedDoc()->GetRootElement();
     nsIFrame* parent = frame->GetParent();
     for (;;) {
@@ -177,17 +195,17 @@ nsresult BoxObject::GetOffsetRect(nsIntR
   return NS_OK;
 }
 
 nsresult BoxObject::GetScreenPosition(nsIntPoint& aPoint) {
   aPoint.x = aPoint.y = 0;
 
   if (!mContent) return NS_ERROR_NOT_INITIALIZED;
 
-  nsIFrame* frame = GetFrame(true);
+  nsIFrame* frame = GetFrameWithFlushPendingNotifications();
   if (frame) {
     CSSIntRect rect = frame->GetScreenRect();
     aPoint.x = rect.x;
     aPoint.y = rect.y;
   }
 
   return NS_OK;
 }
@@ -316,17 +334,17 @@ BoxObject::RemoveProperty(const char16_t
   if (!mPropertyTable) return NS_OK;
 
   nsDependentString propertyName(aPropertyName);
   mPropertyTable->Remove(propertyName);
   return NS_OK;
 }
 
 Element* BoxObject::GetParentBox() {
-  nsIFrame* frame = GetFrame(false);
+  nsIFrame* frame = GetFrame();
   if (!frame) {
     return nullptr;
   }
 
   nsIFrame* parent = frame->GetParent();
   if (!parent) {
     return nullptr;
   }
@@ -336,17 +354,17 @@ Element* BoxObject::GetParentBox() {
   if (parentContent && parentContent->IsElement()) {
     return parentContent->AsElement();
   }
 
   return nullptr;
 }
 
 Element* BoxObject::GetFirstChild() {
-  nsIFrame* frame = GetFrame(false);
+  nsIFrame* frame = GetFrame();
   if (!frame) {
     return nullptr;
   }
 
   nsIFrame* firstFrame = frame->PrincipalChildList().FirstChild();
   if (!firstFrame) {
     return nullptr;
   }
@@ -355,25 +373,25 @@ Element* BoxObject::GetFirstChild() {
   if (content->IsElement()) {
     return content->AsElement();
   }
 
   return nullptr;
 }
 
 Element* BoxObject::GetLastChild() {
-  nsIFrame* frame = GetFrame(false);
+  nsIFrame* frame = GetFrame();
   if (!frame) {
     return nullptr;
   }
   return GetPreviousSibling(frame, nullptr);
 }
 
 Element* BoxObject::GetNextSibling() {
-  nsIFrame* frame = GetFrame(false);
+  nsIFrame* frame = GetFrame();
   if (!frame) {
     return nullptr;
   }
 
   nsIFrame* nextFrame = frame->GetNextSibling();
   if (!nextFrame) {
     return nullptr;
   }
@@ -382,17 +400,17 @@ Element* BoxObject::GetNextSibling() {
   if (content->IsElement()) {
     return content->AsElement();
   }
 
   return nullptr;
 }
 
 Element* BoxObject::GetPreviousSibling() {
-  nsIFrame* frame = GetFrame(false);
+  nsIFrame* frame = GetFrame();
   if (!frame) {
     return nullptr;
   }
   nsIFrame* parentFrame = frame->GetParent();
   if (!parentFrame) {
     return nullptr;
   }
   return GetPreviousSibling(parentFrame, frame);
--- a/layout/xul/BoxObject.h
+++ b/layout/xul/BoxObject.h
@@ -16,19 +16,21 @@
 #include "nsAutoPtr.h"
 #include "nsHashKeys.h"
 #include "nsInterfaceHashtable.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 #include "nsRect.h"
 
 class nsIFrame;
-class nsIPresShell;
 
 namespace mozilla {
+
+class PresShell;
+
 namespace dom {
 
 class Element;
 
 class BoxObject : public nsPIBoxObject, public nsWrapperCache {
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(BoxObject)
   NS_DECL_NSIBOXOBJECT
@@ -36,20 +38,18 @@ class BoxObject : public nsPIBoxObject, 
  public:
   BoxObject();
 
   // nsPIBoxObject
   virtual nsresult Init(Element* aElement) override;
   virtual void Clear() override;
   virtual void ClearCachedValues() override;
 
-  nsIFrame* GetFrame(bool aFlushLayout);
-  nsIPresShell* GetPresShell(bool aFlushLayout);
-  nsresult GetOffsetRect(nsIntRect& aRect);
-  nsresult GetScreenPosition(nsIntPoint& aPoint);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult GetOffsetRect(nsIntRect& aRect);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult GetScreenPosition(nsIntPoint& aPoint);
 
   // Given a parent frame and a child frame, find the frame whose
   // next sibling is the given child frame and return its element
   static Element* GetPreviousSibling(nsIFrame* aParentFrame, nsIFrame* aFrame);
 
   // WebIDL (wraps old impls)
   Element* GetParentObject() const;
   virtual JSObject* WrapObject(JSContext* aCx,
@@ -77,16 +77,21 @@ class BoxObject : public nsPIBoxObject, 
   Element* GetFirstChild();
   Element* GetLastChild();
   Element* GetNextSibling();
   Element* GetPreviousSibling();
 
  protected:
   virtual ~BoxObject();
 
+  nsIFrame* GetFrame() const;
+  MOZ_CAN_RUN_SCRIPT nsIFrame* GetFrameWithFlushPendingNotifications();
+  PresShell* GetPresShell() const;
+  MOZ_CAN_RUN_SCRIPT PresShell* GetPresShellWithFlushPendingNotifications();
+
   nsAutoPtr<nsInterfaceHashtable<nsStringHashKey, nsISupports>> mPropertyTable;
 
   Element* mContent;  // [WEAK]
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -534,18 +534,17 @@ void nsXULPopupManager::PopupResized(nsI
   popup->SetAttr(kNameSpaceID_None, nsGkAtoms::height, height, true);
 }
 
 nsMenuPopupFrame* nsXULPopupManager::GetPopupFrameForContent(
     nsIContent* aContent, bool aShouldFlush) {
   if (aShouldFlush) {
     Document* document = aContent->GetUncomposedDoc();
     if (document) {
-      RefPtr<PresShell> presShell = document->GetPresShell();
-      if (presShell) {
+      if (RefPtr<PresShell> presShell = document->GetPresShell()) {
         presShell->FlushPendingNotifications(FlushType::Layout);
       }
     }
   }
 
   return do_QueryFrame(aContent->GetPrimaryFrame());
 }
 
@@ -967,19 +966,19 @@ void nsXULPopupManager::HidePopup(nsICon
 
     // For menus, popupToHide is always the frontmost item in the list to hide.
     if (aAsynchronous) {
       nsCOMPtr<nsIRunnable> event = new nsXULPopupHidingEvent(
           popupToHide, nextPopup, lastPopup, popupFrame->PopupType(),
           deselectMenu, aIsCancel);
       aPopup->OwnerDoc()->Dispatch(TaskCategory::Other, event.forget());
     } else {
-      FirePopupHidingEvent(popupToHide, nextPopup, lastPopup,
-                           popupFrame->PresContext(), popupFrame->PopupType(),
-                           deselectMenu, aIsCancel);
+      RefPtr<nsPresContext> presContext = popupFrame->PresContext();
+      FirePopupHidingEvent(popupToHide, nextPopup, lastPopup, presContext,
+                           popupFrame->PopupType(), deselectMenu, aIsCancel);
     }
   }
 }
 
 // This is used to hide the popup after a transition finishes.
 class TransitionEnder final : public nsIDOMEventListener {
  protected:
   virtual ~TransitionEnder() {}
@@ -1088,19 +1087,19 @@ void nsXULPopupManager::HidePopupCallbac
       nsCOMPtr<nsIContent> nextPopup;
       if (parent && popupToHide != aLastPopup) nextPopup = parent->Content();
 
       nsMenuPopupFrame* popupFrame = item->Frame();
       nsPopupState state = popupFrame->PopupState();
       if (state == ePopupHiding) return;
       if (state != ePopupInvisible) popupFrame->SetPopupState(ePopupHiding);
 
-      FirePopupHidingEvent(popupToHide, nextPopup, aLastPopup,
-                           popupFrame->PresContext(), foundMenu->PopupType(),
-                           aDeselectMenu, false);
+      RefPtr<nsPresContext> presContext = popupFrame->PresContext();
+      FirePopupHidingEvent(popupToHide, nextPopup, aLastPopup, presContext,
+                           foundMenu->PopupType(), aDeselectMenu, false);
     }
   }
 }
 
 void nsXULPopupManager::HidePopupAfterDelay(nsMenuPopupFrame* aPopup) {
   // Don't close up immediately.
   // Kick off a close timer.
   KillMenuTimer();
@@ -1548,18 +1547,19 @@ already_AddRefed<nsINode> nsXULPopupMana
 
   nsCOMPtr<nsINode> node;
 
   // if mOpeningPopup is set, it means that a popupshowing event is being
   // fired. In this case, just use the cached node, as the popup is not yet in
   // the list of open popups.
   if (mOpeningPopup && mOpeningPopup->GetUncomposedDoc() == aDocument &&
       aIsTooltip == mOpeningPopup->IsXULElement(nsGkAtoms::tooltip)) {
+    nsCOMPtr<nsIContent> openingPopup = mOpeningPopup;
     node = nsMenuPopupFrame::GetTriggerContent(
-        GetPopupFrameForContent(mOpeningPopup, false));
+        GetPopupFrameForContent(openingPopup, false));
   } else {
     nsMenuChainItem* item = mPopups;
     while (item) {
       // look for a popup of the same type and document.
       if ((item->PopupType() == ePopupTypeTooltip) == aIsTooltip &&
           item->Content()->GetUncomposedDoc() == aDocument) {
         node = nsMenuPopupFrame::GetTriggerContent(item->Frame());
         if (node) break;
@@ -2552,27 +2552,27 @@ nsXULPopupShowingEvent::Run() {
                               nullptr);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULPopupHidingEvent::Run() {
-  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-
+  RefPtr<nsXULPopupManager> pm = nsXULPopupManager::GetInstance();
   Document* document = mPopup->GetUncomposedDoc();
   if (pm && document) {
-    nsPresContext* context = document->GetPresContext();
-    if (context) {
-      pm->FirePopupHidingEvent(mPopup, mNextPopup, mLastPopup, context,
+    if (RefPtr<nsPresContext> presContext = document->GetPresContext()) {
+      nsCOMPtr<nsIContent> popup = mPopup;
+      nsCOMPtr<nsIContent> nextPopup = mNextPopup;
+      nsCOMPtr<nsIContent> lastPopup = mLastPopup;
+      pm->FirePopupHidingEvent(popup, nextPopup, lastPopup, presContext,
                                mPopupType, mDeselectMenu, mIsRollup);
     }
   }
-
   return NS_OK;
 }
 
 bool nsXULPopupPositionedEvent::DispatchIfNeeded(nsIContent* aPopup,
                                                  bool aIsContextMenu,
                                                  bool aSelectFirstItem) {
   // The popuppositioned event only fires on arrow panels for now.
   if (aPopup->IsElement() &&
--- a/layout/xul/nsXULPopupManager.h
+++ b/layout/xul/nsXULPopupManager.h
@@ -667,16 +667,17 @@ class nsXULPopupManager final : public n
   nsresult KeyDown(mozilla::dom::KeyboardEvent* aKeyEvent);
   nsresult KeyPress(mozilla::dom::KeyboardEvent* aKeyEvent);
 
  protected:
   nsXULPopupManager();
   ~nsXULPopupManager();
 
   // get the nsMenuPopupFrame, if any, for the given content node
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   nsMenuPopupFrame* GetPopupFrameForContent(nsIContent* aContent,
                                             bool aShouldFlush);
 
   // return the topmost menu, skipping over invisible popups
   nsMenuChainItem* GetTopVisibleMenu();
 
   // Hide all of the visible popups from the given list. This function can
   // cause style changes and frame destruction.
@@ -724,16 +725,17 @@ class nsXULPopupManager final : public n
    * aPopup - the popup to hide
    * aNextPopup - the next popup to hide
    * aLastPopup - the last popup in the chain to hide
    * aPresContext - nsPresContext for the popup's frame
    * aPopupType - the PopupType of the frame.
    * aDeselectMenu - true to unhighlight the menu when hiding it
    * aIsCancel - true if this popup is hiding due to being cancelled.
    */
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   void FirePopupHidingEvent(nsIContent* aPopup, nsIContent* aNextPopup,
                             nsIContent* aLastPopup, nsPresContext* aPresContext,
                             nsPopupType aPopupType, bool aDeselectMenu,
                             bool aIsCancel);
 
   /**
    * Handle keyboard navigation within a menu popup specified by aItem.
    */
--- a/layout/xul/tree/nsTreeBodyFrame.h
+++ b/layout/xul/tree/nsTreeBodyFrame.h
@@ -343,17 +343,17 @@ class nsTreeBodyFrame final : public nsL
   // Update the curpos of the scrollbar.
   void UpdateScrollbars(const ScrollParts& aParts);
 
   // Update the maxpos of the scrollbar.
   void InvalidateScrollbars(const ScrollParts& aParts,
                             AutoWeakFrame& aWeakColumnsFrame);
 
   // Check overflow and generate events.
-  void CheckOverflow(const ScrollParts& aParts);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY void CheckOverflow(const ScrollParts& aParts);
 
   // Calls UpdateScrollbars, Invalidate aNeedsFullInvalidation if true,
   // InvalidateScrollbars and finally CheckOverflow.
   // returns true if the frame is still alive after the method call.
   bool FullScrollbarsUpdate(bool aNeedsFullInvalidation);
 
   // Use to auto-fill some of the common properties without the view having to
   // do it. Examples include container, open, selected, and focus.
--- a/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp
+++ b/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp
@@ -316,39 +316,36 @@ void nsTypeAheadFind::PlayNotFoundSound(
     else
       NS_NewURI(getter_AddRefs(soundURI), mNotFoundSoundURL);
 
     nsCOMPtr<nsIURL> soundURL(do_QueryInterface(soundURI));
     if (soundURL) mSoundInterface->Play(soundURL);
   }
 }
 
-nsresult nsTypeAheadFind::FindItNow(nsIPresShell* aPresShell, bool aIsLinksOnly,
+nsresult nsTypeAheadFind::FindItNow(bool aIsLinksOnly,
                                     bool aIsFirstVisiblePreferred,
                                     bool aFindPrev, uint16_t* aResult) {
   *aResult = FIND_NOTFOUND;
   mFoundLink = nullptr;
   mFoundEditable = nullptr;
   mFoundRange = nullptr;
   mCurrentWindow = nullptr;
   nsCOMPtr<nsIPresShell> startingPresShell(GetPresShell());
   if (!startingPresShell) {
     nsCOMPtr<nsIDocShell> ds = do_QueryReferent(mDocShell);
     NS_ENSURE_TRUE(ds, NS_ERROR_FAILURE);
 
     startingPresShell = ds->GetPresShell();
     mPresShell = do_GetWeakReference(startingPresShell);
   }
 
-  nsCOMPtr<nsIPresShell> presShell(aPresShell);
-
+  nsCOMPtr<nsIPresShell> presShell = startingPresShell;
   if (!presShell) {
-    presShell = startingPresShell;  // this is the current document
-
-    if (!presShell) return NS_ERROR_FAILURE;
+    return NS_ERROR_FAILURE;
   }
 
   // There could be unflushed notifications which hide textareas or other
   // elements that we don't want to find text in.
   presShell->FlushPendingNotifications(mozilla::FlushType::Layout);
 
   RefPtr<nsPresContext> presContext = presShell->GetPresContext();
 
@@ -946,17 +943,17 @@ nsTypeAheadFind::FindAgain(bool aFindBac
                            uint16_t* aResult)
 
 {
   *aResult = FIND_NOTFOUND;
 
   if (!mTypeAheadBuffer.IsEmpty())
     // Beware! This may flush notifications via synchronous
     // ScrollSelectionIntoView.
-    FindItNow(nullptr, aLinksOnly, false, aFindBackwards, aResult);
+    FindItNow(aLinksOnly, false, aFindBackwards, aResult);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTypeAheadFind::Find(const nsAString& aSearchString, bool aLinksOnly,
                       uint16_t* aResult) {
   *aResult = FIND_NOTFOUND;
@@ -1059,18 +1056,17 @@ nsTypeAheadFind::Find(const nsAString& a
         }
       }
     }
   }
 
   // ----------- Find the text! ---------------------
   // Beware! This may flush notifications via synchronous
   // ScrollSelectionIntoView.
-  nsresult rv =
-      FindItNow(nullptr, aLinksOnly, isFirstVisiblePreferred, false, aResult);
+  nsresult rv = FindItNow(aLinksOnly, isFirstVisiblePreferred, false, aResult);
 
   // ---------Handle success or failure ---------------
   if (NS_SUCCEEDED(rv)) {
     if (mTypeAheadBuffer.Length() == 1) {
       // If first letter, store where the first find succeeded
       // (mStartFindRange)
 
       mStartFindRange = nullptr;
--- a/toolkit/components/typeaheadfind/nsTypeAheadFind.h
+++ b/toolkit/components/typeaheadfind/nsTypeAheadFind.h
@@ -61,19 +61,19 @@ class nsTypeAheadFind : public nsITypeAh
   // *aNewRange may not be collapsed.  If you want to collapse it in a
   // particular way, you need to do it yourself.
   bool IsRangeVisible(nsIPresShell *aPresShell, nsPresContext *aPresContext,
                       nsRange *aRange, bool aMustBeVisible,
                       bool aGetTopVisibleLeaf, nsRange **aNewRange,
                       bool *aUsesIndependentSelection);
   bool IsRangeRendered(nsIPresShell *aPresShell, nsPresContext *aPresContext,
                        nsRange *aRange);
-  nsresult FindItNow(nsIPresShell *aPresShell, bool aIsLinksOnly,
-                     bool aIsFirstVisiblePreferred, bool aFindPrev,
-                     uint16_t *aResult);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
+  nsresult FindItNow(bool aIsLinksOnly, bool aIsFirstVisiblePreferred,
+                     bool aFindPrev, uint16_t *aResult);
   nsresult GetSearchContainers(nsISupports *aContainer,
                                nsISelectionController *aSelectionController,
                                bool aIsFirstVisiblePreferred, bool aFindPrev,
                                nsIPresShell **aPresShell,
                                nsPresContext **aPresContext);
 
   // Get the pres shell from mPresShell and return it only if it is still
   // attached to the DOM window.