Bug 1203766 - Part 2: Add an ArenaRefPtr class that can have its pointer cleared out when an object's owning nsPresArena goes away. r=bzbarsky
authorCameron McCormack <cam@mcc.id.au>
Thu, 17 Sep 2015 12:08:19 +1000
changeset 295555 5efb8afff6c73545df0b6f88ab3d4653518b8ae2
parent 295554 76d24976824c2345bb45045e3332fef4e2eb0579
child 295556 3dd4992e71be618115edc551af8c219977fbb506
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs1203766
milestone43.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 1203766 - Part 2: Add an ArenaRefPtr class that can have its pointer cleared out when an object's owning nsPresArena goes away. r=bzbarsky
layout/base/ArenaRefPtr.h
layout/base/ArenaRefPtrInlines.h
layout/base/moz.build
layout/base/nsIPresShell.h
layout/base/nsPresArena.cpp
layout/base/nsPresArena.h
layout/base/nsPresArenaObjectList.h
layout/base/nsPresShell.cpp
new file mode 100644
--- /dev/null
+++ b/layout/base/ArenaRefPtr.h
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=2 sw=2 et tw=78:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/* smart pointer for strong references to nsPresArena-allocated objects
+   that might be held onto until the arena's destruction */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/nsRefPtr.h"
+
+#ifndef mozilla_ArenaRefPtr_h
+#define mozilla_ArenaRefPtr_h
+
+class nsPresArena;
+
+namespace mozilla {
+
+/**
+ * A class for holding strong references to nsPresArena-allocated
+ * objects.
+ *
+ * Since the arena's lifetime is not related to the refcounts
+ * of the objects allocated within it, it is possible to have a strong
+ * reference to an arena-allocated object that lives until the
+ * destruction of the arena.  An ArenaRefPtr acts like a weak reference
+ * in that it will clear its referent if the arena is about to go away.
+ *
+ * T must be a class that has these two methods:
+ *
+ *   static mozilla::ArenaObjectID ArenaObjectID();
+ *   U* Arena();
+ *
+ * where U is a class that has these two methods:
+ *
+ *   void RegisterArenaRefPtr(ArenaRefPtr<T>*);
+ *   void DeregisterArenaRefPtr(ArenaRefPtr<T>*);
+ *
+ * Currently, both nsPresArena and nsIPresShell can be used as U.
+ *
+ * The ArenaObjectID method must return the mozilla::ArenaObjectID that
+ * uniquely identifies T, and the Arena method must return the nsPresArena
+ * (or a proxy for it) in which the object was allocated.
+ */
+template<typename T>
+class ArenaRefPtr
+{
+  friend class ::nsPresArena;
+
+public:
+  ArenaRefPtr()
+  {
+    AssertValidType();
+  }
+
+  template<typename I>
+  MOZ_IMPLICIT ArenaRefPtr(already_AddRefed<I>& aRhs)
+  {
+    AssertValidType();
+    assign(aRhs);
+  }
+
+  template<typename I>
+  MOZ_IMPLICIT ArenaRefPtr(already_AddRefed<I>&& aRhs)
+  {
+    AssertValidType();
+    assign(aRhs);
+  }
+
+  MOZ_IMPLICIT ArenaRefPtr(T* aRhs)
+  {
+    AssertValidType();
+    assign(aRhs);
+  }
+
+  template<typename I>
+  ArenaRefPtr<T>& operator=(already_AddRefed<I>& aRhs)
+  {
+    assign(aRhs);
+    return *this;
+  }
+
+  template<typename I>
+  ArenaRefPtr<T>& operator=(already_AddRefed<I>&& aRhs)
+  {
+    assign(aRhs);
+    return *this;
+  }
+
+  ArenaRefPtr<T>& operator=(T* aRhs)
+  {
+    assign(aRhs);
+    return *this;
+  }
+
+  ~ArenaRefPtr() { assign(nullptr); }
+
+#ifdef MOZ_HAVE_REF_QUALIFIERS
+  operator T*() const & { return get(); }
+  operator T*() const && = delete;
+  explicit operator bool() const { return !!mPtr; }
+  bool operator!() const { return !mPtr; }
+#else
+  operator T*() const { return get(); }
+#endif
+
+  T* operator->() const { return mPtr.operator->(); }
+  T& operator*() const { return *get(); }
+
+  T* get() const { return mPtr; }
+
+private:
+  void AssertValidType();
+
+  /**
+   * Clears the pointer to the arena-allocated object but skips the usual
+   * step of deregistering the ArenaRefPtr from the nsPresArena.  This
+   * method is called by nsPresArena when clearing all registered ArenaRefPtrs
+   * so that it can deregister them all at once, avoiding hash table churn.
+   */
+  void ClearWithoutDeregistering()
+  {
+    mPtr = nullptr;
+  }
+
+  template<typename I>
+  void assign(already_AddRefed<I>& aSmartPtr)
+  {
+    nsRefPtr<T> newPtr(aSmartPtr);
+    assignFrom(newPtr);
+  }
+
+  template<typename I>
+  void assign(already_AddRefed<I>&& aSmartPtr)
+  {
+    nsRefPtr<T> newPtr(aSmartPtr);
+    assignFrom(newPtr);
+  }
+
+  void assign(T* aPtr) { assignFrom(aPtr); }
+
+  template<typename I>
+  void assignFrom(I& aPtr)
+  {
+    if (aPtr == mPtr) {
+      return;
+    }
+    bool sameArena = mPtr && aPtr && mPtr->Arena() == aPtr->Arena();
+    if (mPtr && !sameArena) {
+      MOZ_ASSERT(mPtr->Arena());
+      mPtr->Arena()->DeregisterArenaRefPtr(this);
+    }
+    mPtr = Move(aPtr);
+    if (mPtr && !sameArena) {
+      MOZ_ASSERT(mPtr->Arena());
+      mPtr->Arena()->RegisterArenaRefPtr(this);
+    }
+  }
+
+  nsRefPtr<T> mPtr;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_ArenaRefPtr_h
new file mode 100644
--- /dev/null
+++ b/layout/base/ArenaRefPtrInlines.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=2 sw=2 et tw=78:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/* inline methods that belong in ArenaRefPtr.h, except that they require
+   the inclusion of headers for all types that ArenaRefPtr can handle */
+
+#ifndef mozilla_ArenaRefPtrInlines_h
+#define mozilla_ArenaRefPtrInlines_h
+
+#include "mozilla/ArenaObjectID.h"
+#include "mozilla/Assertions.h"
+#include "nsStyleStruct.h"
+
+namespace mozilla {
+
+template<typename T>
+void
+ArenaRefPtr<T>::AssertValidType()
+{
+#ifdef DEBUG
+  bool ok =
+#define PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT(name_) \
+    T::ArenaObjectID() == eArenaObjectID_##name_ ||
+#include "nsPresArenaObjectList.h"
+#undef PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
+    false;
+  MOZ_ASSERT(ok, "ArenaRefPtr<T> template parameter T must be declared in "
+                 "nsPresArenaObjectList with "
+                 "PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT");
+#endif
+}
+
+} // namespace mozilla
+
+template<typename T>
+void
+nsPresArena::RegisterArenaRefPtr(mozilla::ArenaRefPtr<T>* aPtr)
+{
+  MOZ_ASSERT(!mArenaRefPtrs.Contains(aPtr));
+  mArenaRefPtrs.Put(aPtr, T::ArenaObjectID());
+}
+
+#endif
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -95,16 +95,18 @@ EXPORTS += [
     'StackArena.h',
     'Units.h',
     'UnitTransforms.h',
     'WordMovementType.h',
 ]
 
 EXPORTS.mozilla += [
     'ArenaObjectID.h',
+    'ArenaRefPtr.h',
+    'ArenaRefPtrInlines.h',
     'GeometryUtils.h',
     'PaintTracker.h',
     'RestyleLogging.h',
 ]
 
 UNIFIED_SOURCES += [
     'AccessibleCaret.cpp',
     'AccessibleCaretEventHub.cpp',
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -287,16 +287,28 @@ public:
   {
 #ifdef DEBUG
     mPresArenaAllocCount--;
 #endif
     if (!mIsDestroying)
       mFrameArena.FreeBySize(aSize, aPtr);
   }
 
+  template<typename T>
+  void RegisterArenaRefPtr(mozilla::ArenaRefPtr<T>* aPtr)
+  {
+    mFrameArena.RegisterArenaRefPtr(aPtr);
+  }
+
+  template<typename T>
+  void DeregisterArenaRefPtr(mozilla::ArenaRefPtr<T>* aPtr)
+  {
+    mFrameArena.DeregisterArenaRefPtr(aPtr);
+  }
+
   nsIDocument* GetDocument() const { return mDocument; }
 
   nsPresContext* GetPresContext() const { return mPresContext; }
 
   nsViewManager* GetViewManager() const { return mViewManager; }
 
 #ifdef ACCESSIBILITY
   /**
--- a/layout/base/nsPresArena.cpp
+++ b/layout/base/nsPresArena.cpp
@@ -33,30 +33,72 @@ static const size_t ARENA_PAGE_SIZE = 81
 
 nsPresArena::nsPresArena()
 {
   PL_INIT_ARENA_POOL(&mPool, "PresArena", ARENA_PAGE_SIZE);
 }
 
 nsPresArena::~nsPresArena()
 {
+  ClearArenaRefPtrs();
+
 #if defined(MOZ_HAVE_MEM_CHECKS)
   for (auto iter = mFreeLists.Iter(); !iter.Done(); iter.Next()) {
     FreeList* entry = iter.Get();
     nsTArray<void*>::index_type len;
     while ((len = entry->mEntries.Length())) {
       void* result = entry->mEntries.ElementAt(len - 1);
       entry->mEntries.RemoveElementAt(len - 1);
       MOZ_MAKE_MEM_UNDEFINED(result, entry->mEntrySize);
     }
   }
 #endif
+
   PL_FinishArenaPool(&mPool);
 }
 
+/* inline */ void
+nsPresArena::ClearArenaRefPtrWithoutDeregistering(void* aPtr,
+                                                  ArenaObjectID aObjectID)
+{
+  switch (aObjectID) {
+#define PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT(name_)                     \
+    case eArenaObjectID_##name_:                                              \
+      static_cast<ArenaRefPtr<name_>*>(aPtr)->ClearWithoutDeregistering();    \
+      return;
+#include "nsPresArenaObjectList.h"
+#undef PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
+    default:
+      break;
+  }
+  switch (aObjectID) {
+#define PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(name_)                  \
+    case eArenaObjectID_##name_:                                              \
+      MOZ_ASSERT(false, #name_ " must be declared in nsPresArenaObjectList.h "\
+                        "with PRES_ARENA_OBJECT_SUPPORTS_ARENAREFPTR");       \
+      break;
+#include "nsPresArenaObjectList.h"
+#undef PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
+    default:
+      MOZ_ASSERT(false, "unexpected ArenaObjectID value");
+      break;
+  }
+}
+
+void
+nsPresArena::ClearArenaRefPtrs()
+{
+  for (auto iter = mArenaRefPtrs.Iter(); !iter.Done(); iter.Next()) {
+    void* ptr = iter.Key();
+    ArenaObjectID id = iter.UserData();
+    ClearArenaRefPtrWithoutDeregistering(ptr, id);
+  }
+  mArenaRefPtrs.Clear();
+}
+
 void*
 nsPresArena::Allocate(uint32_t aCode, size_t aSize)
 {
   MOZ_ASSERT(aSize > 0, "PresArena cannot allocate zero bytes");
 
   // We only hand out aligned sizes
   aSize = PL_ARENA_ALIGN(&mPool, aSize);
 
--- a/layout/base/nsPresArena.h
+++ b/layout/base/nsPresArena.h
@@ -6,20 +6,23 @@
  */
 
 /* arena allocation for the frame tree and closely-related objects */
 
 #ifndef nsPresArena_h___
 #define nsPresArena_h___
 
 #include "mozilla/ArenaObjectID.h"
+#include "mozilla/ArenaRefPtr.h"
 #include "mozilla/MemoryChecking.h" // Note: Do not remove this, needed for MOZ_HAVE_MEM_CHECKS below
 #include "mozilla/MemoryReporting.h"
 #include <stdint.h>
 #include "nscore.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 #include "plarena.h"
 
 struct nsArenaMemoryStats;
 
 class nsPresArena {
 public:
@@ -62,26 +65,61 @@ public:
     return Allocate(aID, aSize);
   }
   void FreeByObjectID(mozilla::ArenaObjectID aID, void* aPtr)
   {
     Free(aID, aPtr);
   }
 
   /**
+   * Register an ArenaRefPtr to be cleared when this arena is about to
+   * be destroyed.
+   *
+   * (Defined in ArenaRefPtrInlines.h.)
+   *
+   * @param aPtr The ArenaRefPtr to clear.
+   * @param aObjectID The nsPresArena::ObjectID value that uniquely identifies
+   *   the type of object the ArenaRefPtr holds.
+   */
+  template<typename T>
+  void RegisterArenaRefPtr(mozilla::ArenaRefPtr<T>* aPtr);
+
+  /**
+   * Deregister an ArenaRefPtr that was previously registered with
+   * RegisterArenaRefPtr.
+   */
+  template<typename T>
+  void DeregisterArenaRefPtr(mozilla::ArenaRefPtr<T>* aPtr)
+  {
+    MOZ_ASSERT(mArenaRefPtrs.Contains(aPtr));
+    mArenaRefPtrs.Remove(aPtr);
+  }
+
+  /**
+   * Clears all currently registered ArenaRefPtrs.  This will be called during
+   * the destructor, but can be called by users of nsPresArena who want to
+   * ensure arena-allocated objects are released earlier.
+   */
+  void ClearArenaRefPtrs();
+
+  /**
    * Increment aArenaStats with sizes of interesting objects allocated in this
    * arena and its mOther field with the size of everything else.
    */
   void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
                               nsArenaMemoryStats* aArenaStats);
 
 private:
   void* Allocate(uint32_t aCode, size_t aSize);
   void Free(uint32_t aCode, void* aPtr);
 
+  inline void ClearArenaRefPtrWithoutDeregistering(
+      void* aPtr,
+      mozilla::ArenaObjectID aObjectID);
+
   // All keys to this hash table fit in 32 bits (see below) so we do not
   // bother actually hashing them.
   class FreeList : public PLDHashEntryHdr
   {
   public:
     typedef uint32_t KeyType;
     nsTArray<void *> mEntries;
     size_t mEntrySize;
@@ -106,11 +144,12 @@ private:
     size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     { return mEntries.ShallowSizeOfExcludingThis(aMallocSizeOf); }
 
     enum { ALLOW_MEMMOVE = false };
   };
 
   nsTHashtable<FreeList> mFreeLists;
   PLArenaPool mPool;
+  nsDataHashtable<nsPtrHashKey<void>, mozilla::ArenaObjectID> mArenaRefPtrs;
 };
 
 #endif
--- a/layout/base/nsPresArenaObjectList.h
+++ b/layout/base/nsPresArenaObjectList.h
@@ -5,27 +5,68 @@
 
 /* a list of all types that can be allocated in an nsPresArena, for
    preprocessing */
 
 #ifdef STYLE_STRUCT
 #error Sorry nsPresArenaObjectList.h needs to use STYLE_STRUCT!
 #endif
 
-#if !defined(PRES_ARENA_OBJECT)
-#error Must define PRES_ARENA_OBJECT.
+#ifdef PRES_ARENA_OBJECT
+#if defined(PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT) || \
+    defined(PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT)
+#error Must not define PRES_ARENA_OBJECT along with \
+       PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT or \
+       PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT.
+#endif
+#define PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(name_) PRES_ARENA_OBJECT(name_)
+#define PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT(name_) PRES_ARENA_OBJECT(name_)
+#define DEFINED_PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
+#define DEFINED_PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
+#endif
+
+#ifndef PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
+#define PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(name_) /* nothing */
+#define DEFINED_PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
+#endif
+
+#ifndef PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
+#define PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT(name_) /* nothing */
+#define DEFINED_PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
 #endif
 
-PRES_ARENA_OBJECT(nsLineBox)
-PRES_ARENA_OBJECT(nsRuleNode)
-PRES_ARENA_OBJECT(nsStyleContext)
-PRES_ARENA_OBJECT(nsInheritedStyleData)
-PRES_ARENA_OBJECT(nsResetStyleData)
-PRES_ARENA_OBJECT(nsConditionalResetStyleData)
-PRES_ARENA_OBJECT(nsConditionalResetStyleDataEntry)
-PRES_ARENA_OBJECT(nsFrameList)
-PRES_ARENA_OBJECT(CustomCounterStyle)
-PRES_ARENA_OBJECT(DependentBuiltinCounterStyle)
+// Use PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT to mention an nsPresArena-
+// allocated object that does not support ArenaRefPtr, and use
+// PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT to mention one that does.
+//
+// All PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT classes must be #included into
+// nsPresArena.cpp.
+//
+// Files including nsPresArenaObjectList.h can either define one or both
+// of PRES_ARENA_OBJECT_{WITH,WITHOUT}_ARENAREFPTR_SUPPORT to capture those
+// classes separately, or PRES_ARENA_OBJECT to capture all nsPresArena-
+// allocated classes.
+
+PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsLineBox)
+PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsRuleNode)
+PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsStyleContext)
+PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsInheritedStyleData)
+PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsResetStyleData)
+PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsConditionalResetStyleData)
+PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsConditionalResetStyleDataEntry)
+PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsFrameList)
+PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(CustomCounterStyle)
+PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(DependentBuiltinCounterStyle)
 
 #define STYLE_STRUCT(name_, checkdata_cb_) \
-  PRES_ARENA_OBJECT(nsStyle##name_)
+  PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsStyle##name_)
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
+
+#ifdef DEFINED_PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
+#undef PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
+#undef DEFINED_PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
+#endif
+
+#ifdef DEFINED_PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
+#undef PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
+#undef DEFINED_PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
+#endif
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1226,16 +1226,33 @@ PresShell::Destroy()
 
   if (mViewManager) {
     // Clear the view manager's weak pointer back to |this| in case it
     // was leaked.
     mViewManager->SetPresShell(nullptr);
     mViewManager = nullptr;
   }
 
+  // mFrameArena will be destroyed soon.  Clear out any ArenaRefPtrs
+  // pointing to objects in the arena now.  This is done:
+  //
+  //   (a) before mFrameArena's destructor runs so that our
+  //       mPresArenaAllocCount gets down to 0 and doesn't trip the assertion
+  //       in ~PresShell,
+  //   (b) before the mPresContext->SetShell(nullptr) below, so
+  //       that when we clear the ArenaRefPtrs they'll still be able to
+  //       get back to this PresShell to deregister themselves (e.g. note
+  //       how nsStyleContext::Arena returns the PresShell got from its
+  //       rule node's nsPresContext, which would return null if we'd already
+  //       called mPresContext->SetShell(nullptr)), and
+  //   (c) before the mStyleSet->BeginShutdown() call just below, so that
+  //       the nsStyleContexts don't complain they're being destroyed later
+  //       than the rule tree is.
+  mFrameArena.ClearArenaRefPtrs();
+
   mStyleSet->BeginShutdown();
   nsRefreshDriver* rd = GetPresContext()->RefreshDriver();
 
   // This shell must be removed from the document before the frame
   // hierarchy is torn down to avoid finding deleted frames through
   // this presshell while the frames are being torn down
   if (mDocument) {
     NS_ASSERTION(mDocument->GetShell() == this, "Wrong shell?");