back out bug 774388 and bug 1028383 for intermittent e10s mochitest-2 crashes
authorBenoit Jacob <bjacob@mozilla.com>
Fri, 04 Jul 2014 21:24:32 -0400
changeset 192468 1370a39b329a0e845eff93d4cd0c0c7191cbfde6
parent 192467 da3f630c067607764acb9d02d4f23162f1ff0f38
child 192469 0f1cea1a1a952c84d2a5758dbf9efc3ee6fe5dfc
push id45850
push userbjacob@mozilla.com
push dateSat, 05 Jul 2014 01:24:52 +0000
treeherdermozilla-inbound@1370a39b329a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs774388, 1028383
milestone33.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
back out bug 774388 and bug 1028383 for intermittent e10s mochitest-2 crashes
gfx/layers/AtomicRefCountedWithFinalize.h
gfx/layers/ipc/CompositorChild.h
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/ipc/CompositorParent.h
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/ImageBridgeChild.h
gfx/layers/ipc/ImageBridgeParent.cpp
gfx/layers/ipc/ImageBridgeParent.h
gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h
gfx/layers/moz.build
ipc/glue/ProtocolUtils.cpp
ipc/glue/ProtocolUtils.h
xpcom/build/nsXPComInit.cpp
--- a/gfx/layers/AtomicRefCountedWithFinalize.h
+++ b/gfx/layers/AtomicRefCountedWithFinalize.h
@@ -3,45 +3,30 @@
  * 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/. */
 
 #ifndef MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
 #define MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/NullPtr.h"
-#include "mozilla/Likely.h"
-#include "MainThreadUtils.h"
-#include "base/message_loop.h"
-#include "base/task.h"
 
 namespace mozilla {
 
 template<typename T>
 class AtomicRefCountedWithFinalize
 {
   protected:
     AtomicRefCountedWithFinalize()
       : mRecycleCallback(nullptr)
       , mRefCount(0)
-      , mMessageLoopToPostDestructionTo(nullptr)
     {}
 
     ~AtomicRefCountedWithFinalize() {}
 
-    void SetMessageLoopToPostDestructionTo(MessageLoop* l) {
-      MOZ_ASSERT(NS_IsMainThread());
-      mMessageLoopToPostDestructionTo = l;
-    }
-
-    static void DestroyToBeCalledOnMainThread(T* ptr) {
-      MOZ_ASSERT(NS_IsMainThread());
-      delete ptr;
-    }
-
   public:
     void AddRef() {
       MOZ_ASSERT(mRefCount >= 0);
       ++mRefCount;
     }
 
     void Release() {
       MOZ_ASSERT(mRefCount > 0);
@@ -53,27 +38,17 @@ class AtomicRefCountedWithFinalize
         // Recycle listeners must call ClearRecycleCallback
         // before releasing their strong reference.
         MOZ_ASSERT(mRecycleCallback == nullptr);
 #ifdef DEBUG
         mRefCount = detail::DEAD;
 #endif
         T* derived = static_cast<T*>(this);
         derived->Finalize();
-        if (MOZ_LIKELY(!mMessageLoopToPostDestructionTo)) {
-          delete derived;
-        } else {
-          if (MOZ_LIKELY(NS_IsMainThread())) {
-            delete derived;
-          } else {
-            mMessageLoopToPostDestructionTo->PostTask(
-              FROM_HERE,
-              NewRunnableFunction(&DestroyToBeCalledOnMainThread, derived));
-          }
-        }
+        delete derived;
       } else if (1 == currCount && recycleCallback) {
         T* derived = static_cast<T*>(this);
         recycleCallback(derived, mClosure);
       }
     }
 
     typedef void (*RecycleCallback)(T* aObject, void* aClosure);
     /**
@@ -91,14 +66,13 @@ class AtomicRefCountedWithFinalize
     {
       return !!mRecycleCallback;
     }
 
 private:
     RecycleCallback mRecycleCallback;
     void *mClosure;
     Atomic<int> mRefCount;
-    MessageLoop *mMessageLoopToPostDestructionTo;
 };
 
 }
 
 #endif
--- a/gfx/layers/ipc/CompositorChild.h
+++ b/gfx/layers/ipc/CompositorChild.h
@@ -12,31 +12,29 @@
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/layers/PCompositorChild.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsClassHashtable.h"           // for nsClassHashtable
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsHashKeys.h"                 // for nsUint64HashKey
 #include "nsISupportsImpl.h"            // for NS_INLINE_DECL_REFCOUNTING
-#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 
 class nsIObserver;
 
 namespace mozilla {
 namespace layers {
 
 class ClientLayerManager;
 class CompositorParent;
 struct FrameMetrics;
 
 class CompositorChild MOZ_FINAL : public PCompositorChild
 {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorChild)
-
+  NS_INLINE_DECL_REFCOUNTING(CompositorChild)
 public:
   CompositorChild(ClientLayerManager *aLayerManager);
 
   void Destroy();
 
   /**
    * Lookup the FrameMetrics shared by the compositor process with the
    * associated FrameMetrics::ViewID. The returned FrameMetrics is used
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -48,17 +48,16 @@
 #include "mozilla/layers/CompositorD3D11.h"
 #include "mozilla/layers/CompositorD3D9.h"
 #endif
 #include "GeckoProfiler.h"
 #include "mozilla/ipc/ProtocolTypes.h"
 #include "mozilla/unused.h"
 #include "mozilla/Hal.h"
 #include "mozilla/HalTypes.h"
-#include "mozilla/StaticPtr.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace base;
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 using namespace std;
@@ -69,208 +68,155 @@ CompositorParent::LayerTreeState::LayerT
   , mCrossProcessParent(nullptr)
   , mLayerTree(nullptr)
 {
 }
 
 typedef map<uint64_t, CompositorParent::LayerTreeState> LayerTreeMap;
 static LayerTreeMap sIndirectLayerTrees;
 
-/**
-  * A global map referencing each compositor by ID.
-  *
-  * This map is used by the ImageBridge protocol to trigger
-  * compositions without having to keep references to the
-  * compositor
-  */
-typedef map<uint64_t,CompositorParent*> CompositorMap;
-static CompositorMap* sCompositorMap;
-
-static void CreateCompositorMap()
-{
-  MOZ_ASSERT(!sCompositorMap);
-  sCompositorMap = new CompositorMap;
-}
-
-static void DestroyCompositorMap()
-{
-  MOZ_ASSERT(sCompositorMap);
-  MOZ_ASSERT(sCompositorMap->empty());
-  delete sCompositorMap;
-  sCompositorMap = nullptr;
-}
+// FIXME/bug 774386: we're assuming that there's only one
+// CompositorParent, but that's not always true.  This assumption only
+// affects CrossProcessCompositorParent below.
+static Thread* sCompositorThread = nullptr;
+// manual reference count of the compositor thread.
+static int sCompositorThreadRefCount = 0;
+static MessageLoop* sMainLoop = nullptr;
 
 // See ImageBridgeChild.cpp
 void ReleaseImageBridgeParentSingleton();
 
-class CompositorThreadHolder MOZ_FINAL
+static void DeferredDeleteCompositorParent(CompositorParent* aNowReadyToDie)
 {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorThreadHolder)
+  aNowReadyToDie->Release();
+}
 
-public:
-  CompositorThreadHolder()
-    : mCompositorThread(CreateCompositorThread())
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    MOZ_COUNT_CTOR(CompositorThreadHolder);
+static void DeleteCompositorThread()
+{
+  if (NS_IsMainThread()){
+    ReleaseImageBridgeParentSingleton();
+    delete sCompositorThread;
+    sCompositorThread = nullptr;
+  } else {
+    sMainLoop->PostTask(FROM_HERE, NewRunnableFunction(&DeleteCompositorThread));
   }
-
-  Thread* GetCompositorThread() const {
-    return mCompositorThread;
-  }
+}
 
-private:
-  ~CompositorThreadHolder()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    MOZ_COUNT_DTOR(CompositorThreadHolder);
+static void ReleaseCompositorThread()
+{
+  if(--sCompositorThreadRefCount == 0) {
+    DeleteCompositorThread();
+  }
+}
 
-    DestroyCompositorThread(mCompositorThread);
-  }
-
-  Thread* const mCompositorThread;
+static void SetThreadPriority()
+{
+  hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
+}
 
-  static Thread* CreateCompositorThread();
-  static void DestroyCompositorThread(Thread* aCompositorThread);
-
-  friend class CompositorParent;
-};
+void CompositorParent::StartUp()
+{
+  CreateCompositorMap();
+  CreateThread();
+  sMainLoop = MessageLoop::current();
+}
 
-static StaticRefPtr<CompositorThreadHolder> sCompositorThreadHolder;
-static bool sFinishedCompositorShutDown = false;
-
-/* static */ Thread*
-CompositorThreadHolder::CreateCompositorThread()
+void CompositorParent::ShutDown()
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  DestroyThread();
+  DestroyCompositorMap();
+}
 
-  MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
-
-  Thread* compositorThread = new Thread("Compositor");
+bool CompositorParent::CreateThread()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
+  MOZ_ASSERT(!sCompositorThread);
+  sCompositorThreadRefCount = 1;
+  sCompositorThread = new Thread("Compositor");
 
   Thread::Options options;
   /* Timeout values are powers-of-two to enable us get better data.
      128ms is chosen for transient hangs because 8Hz should be the minimally
      acceptable goal for Compositor responsiveness (normal goal is 60Hz). */
   options.transient_hang_timeout = 128; // milliseconds
   /* 8192ms is chosen for permanent hangs because it's several seconds longer
      than the default hang timeout on major platforms (about 5 seconds). */
   options.permanent_hang_timeout = 8192; // milliseconds
 
-  if (!compositorThread->StartWithOptions(options)) {
-    delete compositorThread;
-    return nullptr;
+  if (!sCompositorThread->StartWithOptions(options)) {
+    delete sCompositorThread;
+    sCompositorThread = nullptr;
+    return false;
   }
 
-  CreateCompositorMap();
-
-  return compositorThread;
-}
-
-/* static */ void
-CompositorThreadHolder::DestroyCompositorThread(Thread* aCompositorThread)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet.");
-
-  DestroyCompositorMap();
-  ReleaseImageBridgeParentSingleton();
-  delete aCompositorThread;
-  sFinishedCompositorShutDown = true;
+  return true;
 }
 
-static Thread* CompositorThread() {
-  return sCompositorThreadHolder ? sCompositorThreadHolder->GetCompositorThread() : nullptr;
-}
-
-static void SetThreadPriority()
-{
-  hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
-}
-
-void CompositorParent::StartUp()
+void CompositorParent::DestroyThread()
 {
-  MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
-  MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
-
-  sCompositorThreadHolder = new CompositorThreadHolder();
-}
-
-void CompositorParent::ShutDown()
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
-  MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!");
-
-  sCompositorThreadHolder = nullptr;
-
-  // No locking is needed around sFinishedCompositorShutDown because it is only
-  // ever accessed on the main thread.
-  while (!sFinishedCompositorShutDown) {
-    NS_ProcessNextEvent(nullptr, true);
-  }
+  NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
+  ReleaseCompositorThread();
 }
 
 MessageLoop* CompositorParent::CompositorLoop()
 {
-  return CompositorThread() ? CompositorThread()->message_loop() : nullptr;
+  return sCompositorThread ? sCompositorThread->message_loop() : nullptr;
 }
 
 CompositorParent::CompositorParent(nsIWidget* aWidget,
                                    bool aUseExternalSurfaceSize,
                                    int aSurfaceWidth, int aSurfaceHeight)
   : mWidget(aWidget)
   , mCurrentCompositeTask(nullptr)
   , mIsTesting(false)
   , mPendingTransaction(0)
   , mPaused(false)
   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   , mEGLSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   , mPauseCompositionMonitor("PauseCompositionMonitor")
   , mResumeCompositionMonitor("ResumeCompositionMonitor")
   , mOverrideComposeReadiness(false)
   , mForceCompositionTask(nullptr)
-  , mCompositorThreadHolder(sCompositorThreadHolder)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(CompositorThread(),
-             "The compositor thread must be Initialized before instanciating a CompositorParent.");
+  MOZ_ASSERT(sCompositorThread != nullptr,
+             "The compositor thread must be Initialized before instanciating a CmpositorParent.");
   MOZ_COUNT_CTOR(CompositorParent);
   mCompositorID = 0;
   // FIXME: This holds on the the fact that right now the only thing that
   // can destroy this instance is initialized on the compositor thread after
   // this task has been processed.
   CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(&AddCompositor,
                                                           this, &mCompositorID));
 
   CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(SetThreadPriority));
 
   mRootLayerTreeID = AllocateLayerTreeId();
   sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
 
   mApzcTreeManager = new APZCTreeManager();
+  ++sCompositorThreadRefCount;
 }
 
 bool
 CompositorParent::IsInCompositorThread()
 {
-  return CompositorThread() && CompositorThread()->thread_id() == PlatformThread::CurrentId();
+  return sCompositorThread && sCompositorThread->thread_id() == PlatformThread::CurrentId();
 }
 
 uint64_t
 CompositorParent::RootLayerTreeId()
 {
   return mRootLayerTreeID;
 }
 
 CompositorParent::~CompositorParent()
 {
-  MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_DTOR(CompositorParent);
+
+  ReleaseCompositorThread();
 }
 
 void
 CompositorParent::Destroy()
 {
   NS_ABORT_IF_FALSE(ManagedPLayerTransactionParent().Length() == 0,
                     "CompositorParent destroyed before managed PLayerTransactionParent");
 
@@ -313,35 +259,29 @@ CompositorParent::RecvWillStop()
     mLayerManager->Destroy();
     mLayerManager = nullptr;
     mCompositionManager = nullptr;
   }
 
   return true;
 }
 
-void CompositorParent::DeferredDestroy()
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  mCompositorThreadHolder = nullptr;
-  Release();
-}
-
 bool
 CompositorParent::RecvStop()
 {
   Destroy();
   // There are chances that the ref count reaches zero on the main thread shortly
   // after this function returns while some ipdl code still needs to run on
   // this thread.
   // We must keep the compositor parent alive untill the code handling message
   // reception is finished on this thread.
-  this->AddRef(); // Corresponds to DeferredDestroy's Release
-  MessageLoop::current()->PostTask(FROM_HERE,
-                                   NewRunnableMethod(this,&CompositorParent::DeferredDestroy));
+  this->AddRef(); // Corresponds to DeferredDeleteCompositorParent's Release
+  CompositorLoop()->PostTask(FROM_HERE,
+                           NewRunnableFunction(&DeferredDeleteCompositorParent,
+                                               this));
   return true;
 }
 
 bool
 CompositorParent::RecvPause()
 {
   PauseComposition();
   return true;
@@ -976,16 +916,37 @@ CompositorParent::AllocPLayerTransaction
 
 bool
 CompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent* actor)
 {
   static_cast<LayerTransactionParent*>(actor)->ReleaseIPDLReference();
   return true;
 }
 
+
+typedef map<uint64_t,CompositorParent*> CompositorMap;
+static CompositorMap* sCompositorMap;
+
+void CompositorParent::CreateCompositorMap()
+{
+  if (sCompositorMap == nullptr) {
+    sCompositorMap = new CompositorMap;
+  }
+}
+
+void CompositorParent::DestroyCompositorMap()
+{
+  if (sCompositorMap != nullptr) {
+    NS_ASSERTION(sCompositorMap->empty(),
+                 "The Compositor map should be empty when destroyed>");
+    delete sCompositorMap;
+    sCompositorMap = nullptr;
+  }
+}
+
 CompositorParent* CompositorParent::GetCompositor(uint64_t id)
 {
   CompositorMap::iterator it = sCompositorMap->find(id);
   return it != sCompositorMap->end() ? it->second : nullptr;
 }
 
 void CompositorParent::AddCompositor(CompositorParent* compositor, uint64_t* outID)
 {
@@ -1111,25 +1072,22 @@ CompositorParent::ComputeRenderIntegrity
  * drive compositing itself.  For that it hands off work to the
  * CompositorParent it's associated with.
  */
 class CrossProcessCompositorParent MOZ_FINAL : public PCompositorParent,
                                                public ShadowLayersManager
 {
   friend class CompositorParent;
 
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CrossProcessCompositorParent)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CrossProcessCompositorParent)
 public:
   CrossProcessCompositorParent(Transport* aTransport, ProcessId aOtherProcess)
     : mTransport(aTransport)
     , mChildProcessId(aOtherProcess)
-    , mCompositorThreadHolder(sCompositorThreadHolder)
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-  }
+  {}
 
   // IToplevelProtocol::CloneToplevel()
   virtual IToplevelProtocol*
   CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds,
                 base::ProcessHandle aPeerProcess,
                 mozilla::ipc::ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
@@ -1182,18 +1140,16 @@ private:
 
   // There can be many CPCPs, and IPDL-generated code doesn't hold a
   // reference to top-level actors.  So we hold a reference to
   // ourself.  This is released (deferred) in ActorDestroy().
   nsRefPtr<CrossProcessCompositorParent> mSelfRef;
   Transport* mTransport;
   // Child side's process Id.
   base::ProcessId mChildProcessId;
-
-  nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
 };
 
 void
 CompositorParent::DidComposite()
 {
   if (mPendingTransaction) {
     unused << SendDidComposite(0, mPendingTransaction);
     mPendingTransaction = 0;
@@ -1215,18 +1171,16 @@ OpenCompositor(CrossProcessCompositorPar
 {
   DebugOnly<bool> ok = aCompositor->Open(aTransport, aHandle, aIOLoop);
   MOZ_ASSERT(ok);
 }
 
 /*static*/ PCompositorParent*
 CompositorParent::Create(Transport* aTransport, ProcessId aOtherProcess)
 {
-  gfxPlatform::InitLayersIPC();
-
   nsRefPtr<CrossProcessCompositorParent> cpcp =
     new CrossProcessCompositorParent(aTransport, aOtherProcess);
   ProcessHandle handle;
   if (!base::OpenProcessHandle(aOtherProcess, &handle)) {
     // XXX need to kill |aOtherProcess|, it's boned
     return nullptr;
   }
 
@@ -1445,24 +1399,26 @@ CrossProcessCompositorParent::GetComposi
 
   MOZ_ASSERT(state->mParent);
   return state->mParent->GetCompositionManager(aLayerTree);
 }
 
 void
 CrossProcessCompositorParent::DeferredDestroy()
 {
-  mCompositorThreadHolder = nullptr;
-  mSelfRef = nullptr;
+  CrossProcessCompositorParent* self;
+  mSelfRef.forget(&self);
+
+  nsCOMPtr<nsIRunnable> runnable =
+    NS_NewNonOwningRunnableMethod(self, &CrossProcessCompositorParent::Release);
+  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
 }
 
 CrossProcessCompositorParent::~CrossProcessCompositorParent()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(XRE_GetIOMessageLoop());
   XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
                                    new DeleteTask<Transport>(mTransport));
 }
 
 IToplevelProtocol*
 CrossProcessCompositorParent::CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds,
                                             base::ProcessHandle aPeerProcess,
                                             mozilla::ipc::ProtocolCloneContext* aCtx)
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -28,17 +28,16 @@
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "mozilla/layers/PCompositorParent.h"
 #include "mozilla/layers/APZTestData.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"
 #include "nsSize.h"                     // for nsIntSize
-#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 
 class CancelableTask;
 class MessageLoop;
 class gfxContext;
 class nsIWidget;
 
 namespace mozilla {
 namespace gfx {
@@ -59,22 +58,20 @@ struct ScopedLayerTreeRegistration
                               Layer* aRoot,
                               GeckoContentController* aController);
   ~ScopedLayerTreeRegistration();
 
 private:
   uint64_t mLayersId;
 };
 
-class CompositorThreadHolder;
-
 class CompositorParent : public PCompositorParent,
                          public ShadowLayersManager
 {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorParent)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorParent)
 
 public:
   CompositorParent(nsIWidget* aWidget,
                    bool aUseExternalSurfaceSize = false,
                    int aSurfaceWidth = -1, int aSurfaceHeight = -1);
 
   // IToplevelProtocol::CloneToplevel()
   virtual IToplevelProtocol*
@@ -164,20 +161,17 @@ public:
   static MessageLoop* CompositorLoop();
 
   /**
    * Creates the compositor thread and the global compositor map.
    */
   static void StartUp();
 
   /**
-   * Waits for all [CrossProcess]CompositorParent's to be gone,
-   * and destroys the compositor thread and global compositor map.
-   *
-   * Does not return until all of that has completed.
+   * Destroys the compositor thread and the global compositor map.
    */
   static void ShutDown();
 
   /**
    * Allocate an ID that can be used to refer to a layer tree and
    * associated resources that live only on the compositor thread.
    *
    * Must run on the content main thread.
@@ -240,18 +234,16 @@ public:
    * Returns true if the calling thread is the compositor thread.
    */
   static bool IsInCompositorThread();
 
 protected:
   // Protected destructor, to discourage deletion outside of Release():
   virtual ~CompositorParent();
 
-  void DeferredDestroy();
-
   virtual PLayerTransactionParent*
     AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
                                  const uint64_t& aId,
                                  TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                  bool* aSuccess) MOZ_OVERRIDE;
   virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE;
   virtual void ScheduleTask(CancelableTask*, int);
   void CompositeCallback();
@@ -263,16 +255,46 @@ protected:
   void InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints);
   void PauseComposition();
   void ResumeComposition();
   void ResumeCompositionAndResize(int width, int height);
   void ForceComposition();
   void CancelCurrentCompositeTask();
 
   /**
+   * Creates a global map referencing each compositor by ID.
+   *
+   * This map is used by the ImageBridge protocol to trigger
+   * compositions without having to keep references to the
+   * compositor
+   */
+  static void CreateCompositorMap();
+  static void DestroyCompositorMap();
+
+  /**
+   * Creates the compositor thread.
+   *
+   * All compositors live on the same thread.
+   * The thread is not lazily created on first access to avoid dealing with
+   * thread safety. Therefore it's best to create and destroy the thread when
+   * we know we areb't using it (So creating/destroying along with gfxPlatform
+   * looks like a good place).
+   */
+  static bool CreateThread();
+
+  /**
+   * Destroys the compositor thread.
+   *
+   * It is safe to call this fucntion more than once, although the second call
+   * will have no effect.
+   * This function is not thread-safe.
+   */
+  static void DestroyThread();
+
+  /**
    * Add a compositor to the global compositor map.
    */
   static void AddCompositor(CompositorParent* compositor, uint64_t* id);
   /**
    * Remove a compositor from the global compositor map.
    */
   static CompositorParent* RemoveCompositor(uint64_t id);
 
@@ -309,17 +331,15 @@ protected:
   uint64_t mCompositorID;
   uint64_t mRootLayerTreeID;
 
   bool mOverrideComposeReadiness;
   CancelableTask* mForceCompositionTask;
 
   nsRefPtr<APZCTreeManager> mApzcTreeManager;
 
-  nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
-
   DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
 };
 
 } // layers
 } // mozilla
 
 #endif // mozilla_layers_CompositorParent_h
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -216,16 +216,17 @@ static void ImageBridgeShutdownStep2(Ree
 {
   ReentrantMonitorAutoEnter autoMon(*aBarrier);
 
   NS_ABORT_IF_FALSE(InImageBridgeChildThread(),
                     "Should be in ImageBridgeChild thread.");
 
   sImageBridgeChildSingleton->SendStop();
 
+  sImageBridgeChildSingleton = nullptr;
   *aDone = true;
   aBarrier->NotifyAll();
 }
 
 // dispatched function
 static void CreateImageClientSync(RefPtr<ImageClient>* result,
                                   ReentrantMonitor* barrier,
                                   CompositableType aType,
@@ -242,24 +243,20 @@ static void ConnectImageBridge(ImageBrid
   MessageLoop *parentMsgLoop = parent->GetMessageLoop();
   ipc::MessageChannel *parentChannel = parent->GetIPCChannel();
   child->Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide);
 }
 
 ImageBridgeChild::ImageBridgeChild()
   : mShuttingDown(false)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
   mTxn = new CompositableTransaction();
 }
 ImageBridgeChild::~ImageBridgeChild()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
   delete mTxn;
 }
 
 void
 ImageBridgeChild::MarkShutDown()
 {
   MOZ_ASSERT(!mShuttingDown);
   mShuttingDown = true;
@@ -545,17 +542,17 @@ ImageBridgeChild::EndTransaction()
   SendPendingAsyncMessge();
 }
 
 
 PImageBridgeChild*
 ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
                                         ProcessId aOtherProcess)
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
 
   gfxPlatform::GetPlatform();
 
   ProcessHandle processHandle;
   if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) {
     return nullptr;
   }
 
@@ -570,17 +567,17 @@ ImageBridgeChild::StartUpInChildProcess(
     NewRunnableFunction(ConnectImageBridgeInChildProcess,
                         aTransport, processHandle));
 
   return sImageBridgeChildSingleton;
 }
 
 void ImageBridgeChild::ShutDown()
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
   if (ImageBridgeChild::IsCreated()) {
     MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown);
 
     {
       ReentrantMonitor barrier("ImageBridge ShutdownStep1 lock");
       ReentrantMonitorAutoEnter autoMon(barrier);
 
       bool done = false;
@@ -598,18 +595,16 @@ void ImageBridgeChild::ShutDown()
       bool done = false;
       sImageBridgeChildSingleton->GetMessageLoop()->PostTask(FROM_HERE,
                       NewRunnableFunction(&ImageBridgeShutdownStep2, &barrier, &done));
       while (!done) {
         barrier.Wait();
       }
     }
 
-    sImageBridgeChildSingleton = nullptr;
-
     delete sImageBridgeChildThread;
     sImageBridgeChildThread = nullptr;
   }
 }
 
 bool ImageBridgeChild::StartUpOnThread(Thread* aThread)
 {
   NS_ABORT_IF_FALSE(aThread, "ImageBridge needs a thread.");
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -12,17 +12,16 @@
 #include "mozilla/RefPtr.h"             // for TemporaryRef
 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
 #include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTrackerHolder
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/CompositorTypes.h"  // for TextureIdentifier, etc
 #include "mozilla/layers/PImageBridgeChild.h"
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
 #include "nsRegion.h"                   // for nsIntRegion
-
 class MessageLoop;
 struct nsIntPoint;
 struct nsIntRect;
 
 namespace base {
 class Thread;
 }
 
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -39,47 +39,35 @@
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 
 std::map<base::ProcessId, ImageBridgeParent*> ImageBridgeParent::sImageBridges;
 
-MessageLoop* ImageBridgeParent::sMainLoop = nullptr;
-
 ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
                                      Transport* aTransport,
                                      ProcessId aChildProcessId)
   : mMessageLoop(aLoop)
   , mTransport(aTransport)
   , mChildProcessId(aChildProcessId)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  sMainLoop = MessageLoop::current();
-
-  // top-level actors must be destroyed on the main thread.
-  SetMessageLoopToPostDestructionTo(sMainLoop);
-
   // creates the map only if it has not been created already, so it is safe
   // with several bridges
   CompositableMap::Create();
   sImageBridges[aChildProcessId] = this;
 }
 
 ImageBridgeParent::~ImageBridgeParent()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
   if (mTransport) {
-    MOZ_ASSERT(XRE_GetIOMessageLoop());
     XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
                                      new DeleteTask<Transport>(mTransport));
   }
-
   sImageBridges.erase(mChildProcessId);
 }
 
 LayersBackend
 ImageBridgeParent::GetCompositorBackendType() const
 {
   return Compositor::GetBackend();
 }
@@ -167,35 +155,20 @@ bool ImageBridgeParent::RecvWillStop()
   ManagedPTextureParent(textures);
   for (unsigned int i = 0; i < textures.Length(); ++i) {
     RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
     tex->DeallocateDeviceData();
   }
   return true;
 }
 
-static void
-ReleaseImageBridgeParent(ImageBridgeParent* aImageBridgeParent)
-{
-  aImageBridgeParent->Release();
-}
-
 bool ImageBridgeParent::RecvStop()
 {
-  // This message just serves as synchronization between the
+  // Nothing to do. This message just serves as synchronization between the
   // child and parent threads during shutdown.
-
-  // There is one thing that we need to do here: temporarily addref, so that
-  // the handling of this sync message can't race with the destruction of
-  // the ImageBridgeParent, which would trigger the dreaded "mismatched CxxStackFrames"
-  // assertion of MessageChannel.
-  AddRef();
-  MessageLoop::current()->PostTask(
-    FROM_HERE,
-    NewRunnableFunction(&ReleaseImageBridgeParent, this));
   return true;
 }
 
 static  uint64_t GenImageContainerID() {
   static uint64_t sNextImageID = 1;
 
   ++sNextImageID;
   return sNextImageID;
@@ -287,20 +260,42 @@ ImageBridgeParent::RecvChildAsyncMessage
   }
   return true;
 }
 
 MessageLoop * ImageBridgeParent::GetMessageLoop() const {
   return mMessageLoop;
 }
 
+class ReleaseRunnable : public nsRunnable
+{
+public:
+  ReleaseRunnable(ImageBridgeParent* aRef)
+    : mRef(aRef)
+  {
+  }
+
+  NS_IMETHOD Run()
+  {
+    mRef->Release();
+    return NS_OK;
+  }
+
+private:
+  ImageBridgeParent* mRef;
+};
+
 void
 ImageBridgeParent::DeferredDestroy()
 {
-  mSelfRef = nullptr;
+  ImageBridgeParent* self;
+  mSelfRef.forget(&self);
+
+  nsCOMPtr<nsIRunnable> runnable = new ReleaseRunnable(self);
+  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
 }
 
 ImageBridgeParent*
 ImageBridgeParent::GetInstance(ProcessId aId)
 {
   NS_ASSERTION(sImageBridges.count(aId) == 1, "ImageBridgeParent for the process");
   return sImageBridges[aId];
 }
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -146,16 +146,14 @@ private:
   // This keeps us alive until ActorDestroy(), at which point we do a
   // deferred destruction of ourselves.
   nsRefPtr<ImageBridgeParent> mSelfRef;
 
   /**
    * Map of all living ImageBridgeParent instances
    */
   static std::map<base::ProcessId, ImageBridgeParent*> sImageBridges;
-
-  static MessageLoop* sMainLoop;
 };
 
 } // layers
 } // mozilla
 
 #endif // gfx_layers_ipc_ImageBridgeParent_h_
deleted file mode 100644
--- a/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* 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/. */
-
-#ifndef THREADSAFEREFCOUNTINGWITHMAINTHREADDESTRUCTION_H_
-#define THREADSAFEREFCOUNTINGWITHMAINTHREADDESTRUCTION_H_
-
-#include "MainThreadUtils.h"
-#include "base/message_loop.h"
-#include "base/task.h"
-
-namespace mozilla {
-namespace layers {
-
-inline MessageLoop* GetMainLoopAssertingMainThread()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  return MessageLoop::current();
-}
-
-inline MessageLoop* GetMainLoop()
-{
-  static MessageLoop* sMainLoop = GetMainLoopAssertingMainThread();
-  return sMainLoop;
-}
-
-struct HelperForMainThreadDestruction
-{
-  HelperForMainThreadDestruction()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    GetMainLoop();
-  }
-
-  ~HelperForMainThreadDestruction()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-  }
-};
-
-} // namespace layers
-} // namespace mozilla
-
-#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(_class) \
-public:                                                                       \
-  NS_METHOD_(MozExternalRefCountType) AddRef(void) {                          \
-    MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class)                                \
-    MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                      \
-    nsrefcnt count = ++mRefCnt;                                               \
-    NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                       \
-    return (nsrefcnt) count;                                                  \
-  }                                                                           \
-  static void DestroyToBeCalledOnMainThread(_class* ptr) {                    \
-    MOZ_ASSERT(NS_IsMainThread());                                            \
-    NS_LOG_RELEASE(ptr, 0, #_class);                                          \
-    delete ptr;                                                               \
-  }                                                                           \
-  NS_METHOD_(MozExternalRefCountType) Release(void) {                         \
-    MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");                          \
-    nsrefcnt count = --mRefCnt;                                               \
-    if (count == 0) {                                                         \
-      if (NS_IsMainThread()) {                                                \
-        NS_LOG_RELEASE(this, 0, #_class);                                     \
-        delete this;                                                          \
-      } else {                                                                \
-        /* no NS_LOG_RELEASE here, will be in the runnable */                 \
-        MessageLoop *l = ::mozilla::layers::GetMainLoop();                    \
-        l->PostTask(FROM_HERE,                                                \
-                    NewRunnableFunction(&DestroyToBeCalledOnMainThread,       \
-                                        this));                               \
-      }                                                                       \
-    } else {                                                                  \
-      NS_LOG_RELEASE(this, count, #_class);                                   \
-    }                                                                         \
-    return count;                                                             \
-  }                                                                           \
-protected:                                                                    \
-  ::mozilla::ThreadSafeAutoRefCnt mRefCnt;                                    \
-private:                                                                      \
-  ::mozilla::layers::HelperForMainThreadDestruction mHelperForMainThreadDestruction; \
-public:
-
-#endif
\ No newline at end of file
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -22,17 +22,16 @@ EXPORTS += [
     'FrameMetrics.h',
     'GrallocImages.h',
     'ImageContainer.h',
     'ImageLayers.h',
     'ImageTypes.h',
     'ipc/CompositorChild.h',
     'ipc/CompositorParent.h',
     'ipc/ShadowLayersManager.h',
-    'ipc/ThreadSafeRefcountingWithMainThreadDestruction.h',
     'Layers.h',
     'LayerScope.h',
     'LayersLogging.h',
     'LayerSorter.h',
     'LayerTreeInvalidation.h',
     'opengl/Composer2D.h',
     'opengl/OGLShaderProgram.h',
     'opengl/TexturePoolOGL.h',
--- a/ipc/glue/ProtocolUtils.cpp
+++ b/ipc/glue/ProtocolUtils.cpp
@@ -14,24 +14,21 @@
 using namespace base;
 using namespace IPC;
 
 namespace mozilla {
 namespace ipc {
 
 IToplevelProtocol::~IToplevelProtocol()
 {
-  MOZ_ASSERT(NS_IsMainThread());
   mOpenActors.clear();
 }
 
 void IToplevelProtocol::AddOpenedActor(IToplevelProtocol* aActor)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
 #ifdef DEBUG
   for (const IToplevelProtocol* actor = mOpenActors.getFirst();
        actor;
        actor = actor->getNext()) {
     NS_ASSERTION(actor != aActor,
                  "Open the same protocol for more than one time");
   }
 #endif
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -16,17 +16,16 @@
 
 #include "IPCMessageStart.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ipc/FileDescriptor.h"
 #include "mozilla/ipc/Shmem.h"
 #include "mozilla/ipc/Transport.h"
 #include "mozilla/ipc/MessageLink.h"
 #include "mozilla/LinkedList.h"
-#include "MainThreadUtils.h"
 
 #if defined(ANDROID) && defined(DEBUG)
 #include <android/log.h>
 #endif
 
 // WARNING: this takes into account the private, special-message-type
 // enum in ipc_channel.h.  They need to be kept in sync.
 namespace {
@@ -183,17 +182,16 @@ public:
  */
 class IToplevelProtocol : public LinkedListElement<IToplevelProtocol>
 {
 protected:
     IToplevelProtocol(ProtocolId aProtoId)
         : mProtocolId(aProtoId)
         , mTrans(nullptr)
     {
-      MOZ_ASSERT(NS_IsMainThread());
     }
 
     ~IToplevelProtocol();
 
     /**
      * Add an actor to the list of actors that have been opened by this
      * protocol.
      */
@@ -209,22 +207,20 @@ public:
 
     ProtocolId GetProtocolId() const { return mProtocolId; }
 
     /**
      * Return first of actors of top level protocols opened by this one.
      */
     IToplevelProtocol* GetFirstOpenedActors()
     {
-        MOZ_ASSERT(NS_IsMainThread());
         return mOpenActors.getFirst();
     }
     const IToplevelProtocol* GetFirstOpenedActors() const
     {
-        MOZ_ASSERT(NS_IsMainThread());
         return mOpenActors.getFirst();
     }
 
     virtual IToplevelProtocol*
     CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
                   base::ProcessHandle aPeerProcess,
                   ProtocolCloneContext* aCtx);
 
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -806,27 +806,27 @@ ShutdownXPCOM(nsIServiceManager* servMgr
             if (NS_SUCCEEDED(rv))
             {
                 (void) observerService->
                     NotifyObservers(mgr, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
                                     nullptr);
             }
         }
 
-        // This must happen after the shutdown of media and widgets, which
-        // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification.
         NS_ProcessPendingEvents(thread);
-        gfxPlatform::ShutdownLayersIPC();
-
         mozilla::scache::StartupCache::DeleteSingleton();
         if (observerService)
             (void) observerService->
                 NotifyObservers(nullptr, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID,
                                 nullptr);
 
+        // This must happen after the shutdown of media and widgets, which
+        // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification.
+        gfxPlatform::ShutdownLayersIPC();
+
         gXPCOMThreadsShutDown = true;
         NS_ProcessPendingEvents(thread);
 
         // Shutdown the timer thread and all timers that might still be alive before
         // shutting down the component manager
         nsTimerImpl::Shutdown();
 
         NS_ProcessPendingEvents(thread);