Backed out 2 changesets (bug 1261347) for test_browserElement_oop_getWebManifest.html ASAN failures
authorWes Kocher <wkocher@mozilla.com>
Wed, 13 Apr 2016 10:55:08 -0700
changeset 330919 0a1722feaf7ba7ceed6b35a00f24d04188e497b5
parent 330918 01eb273e37b6043dd197a539f6d7f99c9eee8ae2
child 330920 bc2373295e31d99f9b870a1253b6e01650df8f31
child 330963 922863fafa0159cdc65ff039829469987b375dcd
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1261347
milestone48.0a1
backs out4b36ba6198154815e958ebeb1e08ce631e36bbb6
685e89b31d6b9814d95c3678b7bf8ecafee245a0
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
Backed out 2 changesets (bug 1261347) for test_browserElement_oop_getWebManifest.html ASAN failures Backed out changeset 4b36ba619815 (bug 1261347) Backed out changeset 685e89b31d6b (bug 1261347) MozReview-Commit-ID: GTd1qTIR3ni
gfx/layers/IPDLActor.h
gfx/layers/ImageContainer.cpp
gfx/layers/client/CompositableClient.cpp
gfx/layers/client/CompositableClient.h
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/LayerTransactionChild.cpp
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
--- a/gfx/layers/IPDLActor.h
+++ b/gfx/layers/IPDLActor.h
@@ -29,187 +29,123 @@ namespace layers {
 /// The actual IPDL protocol must have the following messages:
 ///
 /// child:
 ///   async __delete__();
 /// parent:
 ///   async Destroy();
 ///   sync DestroySynchronously();
 ///
-/// If a sub-class overrides ActorDestroy, it should also call
-/// ChildActor::ActorDestroy from there.
-///
-/// The typical usage of this class looks like the following:
-/// some reference-counted object FooClient holds a reference to a FooChild
-/// actor inheriting from ChildActor<PFooChild>.
-/// Usually, the destruction of FooChild will be triggered by FooClient's
-/// destructor or some other thing that really means that nothing other than
-/// IPDL is holding a pointer to the actor. This is important because we track
-/// this information in mReleased and use it to know when it is safe to delete
-/// the actor. If FooManager::DeallocPFoChild is invoked by IPDL while mReleased
-/// is still false, we don't delete the actor as we usually would. Instead we
-/// set mIPCOpen to false, and ReleaseActor will delete the actor.
 template<typename Protocol>
 class ChildActor : public Protocol
 {
 public:
-  ChildActor()
-  : mReleased(false)
-  , mSentDestroy(false)
-  , mIPCOpen(true)
-  {}
+  ChildActor() : mDestroyed(false) {}
 
-  ~ChildActor() { MOZ_ASSERT(mReleased); }
+  ~ChildActor() { MOZ_ASSERT(mDestroyed); }
 
   /// Check the return of CanSend before sending any message!
-  bool CanSend() const { return !mSentDestroy && mIPCOpen; }
+  bool CanSend() const { return !mDestroyed; }
 
-  /// Return true if this actor is still connected to the IPDL system.
-  bool IPCOpen() const { return mIPCOpen; }
+  /// The normal way to destroy the actor.
+  ///
+  /// This will asynchronously send a Destroy message to the parent actor, whom
+  /// will send the delete message.
+  void Destroy(CompositableForwarder* aFwd = nullptr)
+  {
+    MOZ_ASSERT(!mDestroyed);
+    if (!mDestroyed) {
+      mDestroyed = true;
+      DestroyManagees();
+      if (!aFwd || !aFwd->DestroyInTransaction(this, false)) {
+        this->SendDestroy();
+      }
+    }
+  }
 
-  /// Return true if the actor was released (nothing holds on to the actor
-  /// except IPDL, and the actor will most likely receive the __delete__
-  /// message soon. Useful to know whether we can delete the actor when
-  /// IPDL shuts down.
-  bool Released() const { return mReleased; }
+  /// The ugly and slow way to destroy the actor.
+  ///
+  /// This will block until the Parent actor has handled the Destroy message,
+  /// and then start the asynchronous handshake (and destruction will already
+  /// be done on the parent side, when the async part happens).
+  void DestroySynchronously(CompositableForwarder* aFwd = nullptr)
+  {
+    MOZ_PERFORMANCE_WARNING("gfx", "IPDL actor requires synchronous deallocation");
+    MOZ_ASSERT(!mDestroyed);
+    if (!mDestroyed) {
+      DestroyManagees();
+      mDestroyed = true;
+      if (!aFwd || !aFwd->DestroyInTransaction(this, true)) {
+        this->SendDestroySync();
+        this->SendDestroy();
+      }
+    }
+  }
 
   /// If the transaction that was supposed to destroy the texture fails for
   /// whatever reason, fallback to destroying the actor synchronously.
   static bool DestroyFallback(Protocol* aActor)
   {
     return aActor->SendDestroySync();
   }
 
-  typedef ipc::IProtocolManager<ipc::IProtocol>::ActorDestroyReason Why;
-
-  virtual void ActorDestroy(Why) override
-  {
-    mIPCOpen = false;
-  }
-
-  /// Call this during shutdown only, if we need to destroy this
-  /// actor but the object paired with the actor isn't destroyed yet.
-  void ForceActorShutdown()
-  {
-    if (mIPCOpen && !mSentDestroy) {
-      this->SendDestroy();
-      mSentDestroy = true;
-    }
-  }
-
-  /// The normal way to destroy the actor.
-  ///
-  /// This will asynchronously send a Destroy message to the parent actor, whom
-  /// will send the delete message.
-  /// Nothing other than IPDL should hold a pointer to the actor after this is
-  /// called.
-  void ReleaseActor(CompositableForwarder* aFwd = nullptr)
-  {
-    if (!IPCOpen()) {
-      mReleased = true;
-      delete this;
-      return;
-    }
-
-    Destroy(aFwd, false);
-  }
-
-  /// The ugly and slow way to destroy the actor.
-  ///
-  /// This will block until the Parent actor has handled the Destroy message,
-  /// and then start the asynchronous handshake (and destruction will already
-  /// be done on the parent side, when the async part happens).
-  /// Nothing other than IPDL should hold a pointer to the actor after this is
-  /// called.
-  void ReleaseActorSynchronously(CompositableForwarder* aFwd = nullptr)
-  {
-    if (!IPCOpen()) {
-      mReleased = true;
-      delete this;
-      return;
-    }
-
-    Destroy(aFwd, true);
-  }
-
-protected:
-
-  void Destroy(CompositableForwarder* aFwd = nullptr, bool synchronously = false)
-  {
-    MOZ_ASSERT(mIPCOpen);
-    MOZ_ASSERT(!mReleased);
-    if (mReleased) {
-      return;
-    }
-    mReleased = true;
-
-    if (!aFwd || !aFwd->DestroyInTransaction(this, synchronously)) {
-      if (synchronously) {
-        MOZ_PERFORMANCE_WARNING("gfx", "IPDL actor requires synchronous deallocation");
-        this->SendDestroySync();
-      } else {
-        this->SendDestroy();
-      }
-    }
-    mSentDestroy = true;
-  }
+  /// Override this if the protocol manages other protocols, and destroy the
+  /// managees from there
+  virtual void DestroyManagees() {}
 
 private:
-  bool mReleased;
-  bool mSentDestroy;
-  bool mIPCOpen;
+  bool mDestroyed;
 };
 
-
 /// A base class to facilitate the deallocation of IPDL actors.
 ///
 /// Implements the parent side of the simple deallocation handshake.
 /// Override the Destroy method rather than the ActorDestroy method.
 template<typename Protocol>
 class ParentActor : public Protocol
 {
 public:
-  ParentActor() : mReleased(false) {}
+  ParentActor() : mDestroyed(false) {}
 
-  ~ParentActor() { MOZ_ASSERT(mReleased); }
+  ~ParentActor() { MOZ_ASSERT(mDestroyed); }
 
-  bool CanSend() const { return !mReleased; }
+  bool CanSend() const { return !mDestroyed; }
 
   // Override this rather than ActorDestroy
   virtual void Destroy() {}
 
   virtual bool RecvDestroy() override
   {
-    if (!mReleased) {
+    if (!mDestroyed) {
       Destroy();
-      mReleased = true;
+      mDestroyed = true;
     }
     Unused << Protocol::Send__delete__(this);
     return true;
   }
 
   virtual bool RecvDestroySync() override
   {
-    if (!mReleased) {
+    if (!mDestroyed) {
       Destroy();
-      mReleased = true;
+      mDestroyed = true;
     }
     return true;
   }
 
   typedef ipc::IProtocolManager<ipc::IProtocol>::ActorDestroyReason Why;
 
   virtual void ActorDestroy(Why) override
   {
-    if (!mReleased) {
+    if (!mDestroyed) {
       Destroy();
-      mReleased = true;
+      mDestroyed = true;
     }
   }
 
 private:
-  bool mReleased;
+  bool mDestroyed;
 };
 
 } // namespace
 } // namespace
 
 #endif
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -196,25 +196,16 @@ ImageContainer::ImageContainer(Mode flag
         break;
     }
   }
 }
 
 ImageContainer::~ImageContainer()
 {
   if (IsAsync()) {
-
-    if (gfxPlatform::IPCAlreadyShutDown()) {
-      printf_stderr("!![ImageBridge] an ImageContainer is Destroyed late "
-                    "during shutdown!!\n");
-#ifdef GFX_STRICT_SHUTDOWN
-      MOZ_CRASH("This ImageContainer is deleted too late.");
-#endif
-    }
-
     mIPDLChild->ForgetImageContainer();
     ImageBridgeChild::DispatchReleaseImageClient(mImageClient, mIPDLChild);
   }
 }
 
 RefPtr<PlanarYCbCrImage>
 ImageContainer::CreatePlanarYCbCrImage()
 {
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -40,24 +40,21 @@ public:
     MOZ_COUNT_CTOR(CompositableChild);
   }
 
   virtual ~CompositableChild()
   {
     MOZ_COUNT_DTOR(CompositableChild);
   }
 
-  virtual void ActorDestroy(ActorDestroyReason aWhy) override {
+  virtual void ActorDestroy(ActorDestroyReason) override {
     DestroyAsyncTransactionTrackersHolder();
-    ChildActor::ActorDestroy(aWhy);
-  }
-
-  static CompositableChild* Cast(PCompositableChild* aActor)
-  {
-    return static_cast<CompositableChild*>(aActor);
+    if (mCompositableClient) {
+      mCompositableClient->mCompositableChild = nullptr;
+    }
   }
 
   CompositableClient* mCompositableClient;
 
   uint64_t mAsyncID;
 };
 
 void
@@ -74,89 +71,76 @@ RemoveTextureFromCompositableTracker::Re
   } else {
     mTextureClient = nullptr;
   }
 }
 
 /* static */ void
 CompositableClient::TransactionCompleteted(PCompositableChild* aActor, uint64_t aTransactionId)
 {
-  CompositableChild* child = CompositableChild::Cast(aActor);
+  CompositableChild* child = static_cast<CompositableChild*>(aActor);
   child->TransactionCompleteted(aTransactionId);
 }
 
 /* static */ void
 CompositableClient::HoldUntilComplete(PCompositableChild* aActor, AsyncTransactionTracker* aTracker)
 {
-  CompositableChild* child = CompositableChild::Cast(aActor);
+  CompositableChild* child = static_cast<CompositableChild*>(aActor);
   child->HoldUntilComplete(aTracker);
 }
 
 /* static */ uint64_t
 CompositableClient::GetTrackersHolderId(PCompositableChild* aActor)
 {
-  CompositableChild* child = CompositableChild::Cast(aActor);
+  CompositableChild* child = static_cast<CompositableChild*>(aActor);
   return child->GetId();
 }
 
 /* static */ PCompositableChild*
 CompositableClient::CreateIPDLActor()
 {
   return new CompositableChild();
 }
 
 /* static */ bool
-CompositableClient::DeallocIPDLActor(PCompositableChild* aActor)
+CompositableClient::DestroyIPDLActor(PCompositableChild* actor)
 {
-  MOZ_ASSERT(aActor);
-
-  auto actor = CompositableChild::Cast(aActor);
-  if (actor->Released()) {
-    delete actor;
-  }
-
+  delete actor;
   return true;
 }
 
 void
 CompositableClient::InitIPDLActor(PCompositableChild* aActor, uint64_t aAsyncID)
 {
   MOZ_ASSERT(aActor);
-  CompositableChild* child = CompositableChild::Cast(aActor);
+  CompositableChild* child = static_cast<CompositableChild*>(aActor);
   mCompositableChild = child;
   child->mCompositableClient = this;
   child->mAsyncID = aAsyncID;
 }
 
 /* static */ CompositableClient*
 CompositableClient::FromIPDLActor(PCompositableChild* aActor)
 {
   MOZ_ASSERT(aActor);
-  return CompositableChild::Cast(aActor)->mCompositableClient;
+  return static_cast<CompositableChild*>(aActor)->mCompositableClient;
 }
 
 CompositableClient::CompositableClient(CompositableForwarder* aForwarder,
                                        TextureFlags aTextureFlags)
 : mCompositableChild(nullptr)
 , mForwarder(aForwarder)
 , mTextureFlags(aTextureFlags)
 {
   MOZ_COUNT_CTOR(CompositableClient);
 }
 
 CompositableClient::~CompositableClient()
 {
   MOZ_COUNT_DTOR(CompositableClient);
-
-#ifdef GFX_STRICT_SHUTDOWN
-  if (gfxPlatform::IPCAlreadyShutDown()) {
-    MOZ_CRASH("This CompositableClient is deleted too late.");
-  }
-#endif
-
   Destroy();
 }
 
 LayersBackend
 CompositableClient::GetCompositorBackendType() const
 {
   return mForwarder->GetCompositorBackendType();
 }
@@ -185,65 +169,36 @@ CompositableClient::Connect(ImageContain
 }
 
 bool
 CompositableClient::IsConnected() const
 {
   return mCompositableChild && mCompositableChild->CanSend();
 }
 
-// static
-void
-CompositableClient::ForceIPDLActorShutdown(PCompositableChild* aActor,
-                                           const char* const aProtocolName)
-{
-  if (!aActor) {
-    return;
-  }
-
-  auto actor = CompositableChild::Cast(aActor);
-  if (actor->CanSend()) {
-#ifdef DEBUG
-    // Making it an assertion would blow up too often during test runs so
-    // let's keep it a simple printf for now. This is happening during shutdown
-    // so we don't have to worry too much about printf being slow.
-    // More involved reporting like crashstats annotations would be too much noise
-    // at this point.
-    printf_stderr("!![%s] A CompositableClient is destroyed late during shutdown!!\n",
-                  aProtocolName);
-#endif
-
-    // Do not access the CompositableClient from here.
-    // Do not call Destroy() either because that's how we know whether the
-    // CompositableClient's destructor has run.
-    actor->ForceActorShutdown();
-  }
-}
-
 void
 CompositableClient::Destroy()
 {
-  if (!mCompositableChild) {
+  if (!IsConnected()) {
     return;
   }
 
   // Send pending AsyncMessages before deleting CompositableChild since the former
   // might have references to the latter.
   mForwarder->SendPendingAsyncMessges();
 
   mCompositableChild->mCompositableClient = nullptr;
-  mCompositableChild->ReleaseActor(mForwarder);
+  mCompositableChild->Destroy(mForwarder);
   mCompositableChild = nullptr;
 }
 
 bool
 CompositableClient::DestroyFallback(PCompositableChild* aActor)
 {
-  CompositableChild::Cast(aActor)->ReleaseActorSynchronously();
-  return true;
+  return aActor->SendDestroySync();
 }
 
 uint64_t
 CompositableClient::GetAsyncID() const
 {
   if (mCompositableChild) {
     return mCompositableChild->mAsyncID;
   }
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -217,26 +217,17 @@ public:
    *
    * CompositableChild is an implementation detail of CompositableClient that is not
    * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
    * are for use with the managing IPDL protocols only (so that they can
    * implement AllocCompositableChild and DeallocPCompositableChild).
    */
   static PCompositableChild* CreateIPDLActor();
 
-  static bool DeallocIPDLActor(PCompositableChild* actor);
-
-  /// Ideally we would not need this. When we shut top-level IPDL protocols down,
-  /// the remaining managed protocols need to be destroyed synchronously. We'd
-  /// It'd be better if all ImageClients were alread destroyed by that time.
-  /// Call this during shutdown instead of trying to access the CompositableClient
-  /// since the latter may be about to get destroyed and we don't know for sure
-  /// on which thread.
-  static void ForceIPDLActorShutdown(PCompositableChild* aActor,
-                                     const char* const aProtocolName);
+  static bool DestroyIPDLActor(PCompositableChild* actor);
 
   void InitIPDLActor(PCompositableChild* aActor, uint64_t aAsyncID = 0);
 
   static void TransactionCompleteted(PCompositableChild* aActor, uint64_t aTransactionId);
 
   static void HoldUntilComplete(PCompositableChild* aActor, AsyncTransactionTracker* aTracker);
 
   static uint64_t GetTrackersHolderId(PCompositableChild* aActor);
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -67,17 +67,17 @@ namespace layers {
 
 using namespace mozilla::ipc;
 using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
 struct TextureDeallocParams
 {
   TextureData* data;
-  TextureChild* actor;
+  RefPtr<TextureChild> actor;
   RefPtr<ClientIPCAllocator> allocator;
   bool clientDeallocation;
   bool syncDeallocation;
   bool workAroundSharedSurfaceOwnershipIssue;
 };
 
 void DeallocateTextureClient(TextureDeallocParams params);
 
@@ -95,70 +95,99 @@ void DeallocateTextureClient(TextureDeal
 class TextureChild final : public ChildActor<PTextureChild>
 {
   ~TextureChild()
   {
     // We should have deallocated mTextureData in ActorDestroy
     MOZ_ASSERT(!mTextureData);
   }
 public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureChild)
 
   TextureChild()
   : mForwarder(nullptr)
+  , mMonitor("TextureChild")
   , mTextureClient(nullptr)
   , mTextureData(nullptr)
-  , mTextureClientDestroyed(false)
+  , mDestroyed(false)
   , mMainThreadOnly(false)
+  , mIPCOpen(false)
   , mOwnsTextureData(false)
-  , mSyncDeallocation(false)
   {}
 
   bool Recv__delete__() override { return true; }
 
   bool RecvCompositorRecycle() override
   {
     RECYCLE_LOG("[CLIENT] Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get());
     mWaitForRecycle = nullptr;
     return true;
   }
 
   void WaitForCompositorRecycle()
   {
     {
-      mWaitForRecycle = mTextureClientDestroyed ? nullptr : mTextureClient;
+      MonitorAutoLock mon(mMonitor);
+      mWaitForRecycle = mDestroyed ? nullptr : mTextureClient;
     }
     RECYCLE_LOG("[CLIENT] Wait for recycle %p\n", mWaitForRecycle.get());
     MOZ_ASSERT(CanSend());
     SendClientRecycle();
   }
 
   void CancelWaitForCompositorRecycle()
   {
     RECYCLE_LOG("[CLIENT] Cancelling wait for recycle %p\n", mWaitForRecycle.get());
     {
+      MonitorAutoLock mon(mMonitor);
       mWaitForRecycle = nullptr;
     }
   }
 
   CompositableForwarder* GetForwarder() { return mForwarder; }
 
   ClientIPCAllocator* GetAllocator() { return mForwarder; }
 
   void ActorDestroy(ActorDestroyReason why) override;
 
+  bool IPCOpen() const { return mIPCOpen; }
+
+private:
+
+  // AddIPDLReference and ReleaseIPDLReference are only to be called by CreateIPDLActor
+  // and DestroyIPDLActor, respectively. We intentionally make them private to prevent misuse.
+  // The purpose of these methods is to be aware of when the IPC system around this
+  // actor goes down: mIPCOpen is then set to false.
+  void AddIPDLReference() {
+    MOZ_ASSERT(mIPCOpen == false);
+    mIPCOpen = true;
+    AddRef();
+  }
+  void ReleaseIPDLReference() {
+    MOZ_ASSERT(mIPCOpen == true);
+    mIPCOpen = false;
+    Release();
+  }
+
+  void SetTextureClient(TextureClient* aTextureClient) {
+    MonitorAutoLock mon(mMonitor);
+    mTextureClient = aTextureClient;
+  }
+
   RefPtr<CompositableForwarder> mForwarder;
-  RefPtr<ClientIPCAllocator> mAllocator;
   RefPtr<TextureClient> mWaitForRecycle;
 
+  // Monitor protecting mTextureClient.
+  Monitor mMonitor;
   TextureClient* mTextureClient;
   TextureData* mTextureData;
-  Atomic<bool> mTextureClientDestroyed;
+  Atomic<bool> mDestroyed;
   bool mMainThreadOnly;
+  bool mIPCOpen;
   bool mOwnsTextureData;
-  bool mSyncDeallocation;
 
   friend class TextureClient;
   friend void DeallocateTextureClient(TextureDeallocParams params);
 };
 
 
 static void DestroyTextureData(TextureData* aTextureData, ClientIPCAllocator* aAllocator,
                                bool aDeallocate, bool aMainThreadOnly)
@@ -188,90 +217,27 @@ TextureChild::ActorDestroy(ActorDestroyR
 {
   PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS);
   mWaitForRecycle = nullptr;
 
   if (mTextureData) {
     DestroyTextureData(mTextureData, GetAllocator(), mOwnsTextureData, mMainThreadOnly);
     mTextureData = nullptr;
   }
-
-  ChildActor::ActorDestroy(why);
 }
 
 void DeallocateTextureClientSyncProxy(TextureDeallocParams params,
                                         ReentrantMonitor* aBarrier, bool* aDone)
 {
   DeallocateTextureClient(params);
   ReentrantMonitorAutoEnter autoMon(*aBarrier);
   *aDone = true;
   aBarrier->NotifyAll();
 }
 
-// This must not be called off the IPDL thread.
-static
-void DestroyTextureActorAndSharedData(TextureChild* aActor)
-{
-  MOZ_ASSERT(aActor);
-  if (!aActor->CanSend()) {
-    return;
-  }
-
-  RefPtr<CompositableForwarder> forwarder = aActor->mForwarder;
-
-  if (aActor->mSyncDeallocation) {
-    MOZ_PERFORMANCE_WARNING("gfx",
-      "TextureClient/Host pair requires synchronous deallocation");
-
-    RefPtr<ClientIPCAllocator> allocator = aActor->GetAllocator();
-    TextureData* data = aActor->mTextureData;
-    bool mainThreadOnly = aActor->mMainThreadOnly;
-    bool clientDeallocation = aActor->mOwnsTextureData;
-
-    // Null out mTextureData so that ActorDestory doesn't call
-    // DestroyTextureData a second time.
-    aActor->mTextureData = nullptr;
-
-    // aActor may get deleted in ReleaseActorSynchronously.
-    aActor->ReleaseActorSynchronously(forwarder);
-
-    if (data) {
-      DestroyTextureData(data, allocator, clientDeallocation, mainThreadOnly);
-    }
-
-  } else {
-    // aActor may get deleted in ReleaseActor.
-    aActor->ReleaseActor(forwarder);
-    // DestroyTextureData will be called by TextureChild::ActorDestroy
-  }
-}
-
-void TextureClient::ForceIPDLActorShutdown(PTextureChild* aActor,
-                                           const char* const aProtocolName)
-{
-  if (!aActor) {
-    return;
-  }
-  auto actor = static_cast<TextureChild*>(aActor);
-
-#ifdef DEBUG
-  // Making it an assertion would blow up too often during test runs so
-  // let's keep it a simple printf for now. This is happening during shutdown
-  // so we don't have to worry too much about printf being slow.
-  // More involved reporting like crashstats annotations would be too much noise
-  // at this point.
-  if (actor->CanSend()) {
-    printf_stderr("!![%s] A TextureClient is destroyed late during shutdown!!\n",
-                  aProtocolName);
-  }
-#endif
-
-  DestroyTextureActorAndSharedData(actor);
-}
-
 /// The logic for synchronizing a TextureClient's deallocation goes here.
 ///
 /// This funciton takes care of dispatching work to the right thread using
 /// a synchronous proxy if needed, and handles client/host deallocation.
 void
 DeallocateTextureClient(TextureDeallocParams params)
 {
   if (!params.actor && !params.data) {
@@ -282,17 +248,17 @@ DeallocateTextureClient(TextureDeallocPa
   TextureChild* actor = params.actor;
   MessageLoop* ipdlMsgLoop = nullptr;
 
   if (params.allocator) {
     ipdlMsgLoop = params.allocator->AsClientAllocator()->GetMessageLoop();
     if (!ipdlMsgLoop) {
       // An allocator with no message loop means we are too late in the shutdown
       // sequence.
-      printf_stderr("!!A TextureClient destroyed after its IPDL thread !!\n");
+      gfxCriticalError() << "Texture deallocated too late during shutdown";
       return;
     }
   }
 
   // First make sure that the work is happening on the IPDL thread.
   if (ipdlMsgLoop && MessageLoop::current() != ipdlMsgLoop) {
     if (params.syncDeallocation) {
       bool done = false;
@@ -333,27 +299,45 @@ DeallocateTextureClient(TextureDeallocPa
     // our data. This is specific to the gralloc SharedSurface.
     bool shouldDeallocate = !params.workAroundSharedSurfaceOwnershipIssue;
     DestroyTextureData(params.data, params.allocator,
                        shouldDeallocate,
                        false);  // main-thread deallocation
     return;
   }
 
-  DestroyTextureActorAndSharedData(actor);
+  if (!actor->IPCOpen()) {
+    // The actor is already deallocated which probably means there was a shutdown
+    // race causing this function to be called concurrently which is bad!
+    gfxCriticalError() << "Racy texture deallocation";
+    return;
+  }
+
+  if (params.syncDeallocation) {
+    MOZ_PERFORMANCE_WARNING("gfx",
+      "TextureClient/Host pair requires synchronous deallocation");
+    actor->DestroySynchronously(actor->GetForwarder());
+    DestroyTextureData(params.data, params.allocator, params.clientDeallocation,
+                       actor->mMainThreadOnly);
+  } else {
+    actor->mTextureData = params.data;
+    actor->mOwnsTextureData = params.clientDeallocation;
+    actor->Destroy(actor->GetForwarder());
+    // DestroyTextureData will be called by TextureChild::ActorDestroy
+  }
 }
 
 void TextureClient::Destroy(bool aForceSync)
 {
   MOZ_ASSERT(!IsLocked());
 
-  TextureChild* actor = mActor;
+  RefPtr<TextureChild> actor = mActor;
   mActor = nullptr;
 
-  if (actor && !actor->mTextureClientDestroyed.compareExchange(false, true)) {
+  if (actor && !actor->mDestroyed.compareExchange(false, true)) {
     actor = nullptr;
   }
 
   TextureData* data = mData;
   if (!mWorkaroundAnnoyingSharedSurfaceLifetimeIssues) {
     mData = nullptr;
   }
 
@@ -469,22 +453,16 @@ gfx::SurfaceFormat
 TextureClient::GetFormat() const
 {
   MOZ_ASSERT(IsValid());
   return mData->GetFormat();
 }
 
 TextureClient::~TextureClient()
 {
-#ifdef GFX_STRICT_SHUTDOWN
-  if (gfxPlatform::IPCAlreadyShutDown()) {
-    MOZ_CRASH("This TextureClient is deleted too late.");
-  }
-#endif
-
   Destroy(false);
 }
 
 void
 TextureClient::UpdateFromSurface(gfx::SourceSurface* aSurface)
 {
   MOZ_ASSERT(IsValid());
   MOZ_ASSERT(mIsLocked);
@@ -600,84 +578,80 @@ TextureClient::WaitForBufferOwnership(bo
   }
 #endif
 }
 
 // static
 PTextureChild*
 TextureClient::CreateIPDLActor()
 {
-  return new TextureChild();
+  TextureChild* c = new TextureChild();
+  c->AddIPDLReference();
+  return c;
 }
 
 // static
 bool
-TextureClient::DeallocIPDLActor(PTextureChild* aActor)
+TextureClient::DestroyIPDLActor(PTextureChild* actor)
 {
-  auto actor = static_cast<TextureChild*>(aActor);
-  if (actor->Released()) {
-    delete actor;
-  }
-
+  static_cast<TextureChild*>(actor)->ReleaseIPDLReference();
   return true;
 }
 
 // static
 TextureClient*
 TextureClient::AsTextureClient(PTextureChild* actor)
 {
   if (!actor) {
     return nullptr;
   }
   TextureChild* tc = static_cast<TextureChild*>(actor);
-  if (tc->mTextureClientDestroyed) {
-    // This is mostly a band aid. Nothing prevents the texture to be destroyed
-    // on another thread just after this check is performed.
+  if (tc->mDestroyed) {
     return nullptr;
   }
 
   return tc->mTextureClient;
 }
 
 bool
 TextureClient::IsSharedWithCompositor() const {
-  return mActor && mActor->CanSend();
+  return mActor && mActor->IPCOpen();
 }
 
 void
 TextureClient::AddFlags(TextureFlags aFlags)
 {
   MOZ_ASSERT(!IsSharedWithCompositor() ||
              ((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
   mFlags |= aFlags;
-  if (IsValid() && mActor && mActor->CanSend()) {
+  if (IsValid() && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
     mActor->SendRecycleTexture(mFlags);
   }
 }
 
 void
 TextureClient::RemoveFlags(TextureFlags aFlags)
 {
   MOZ_ASSERT(!IsSharedWithCompositor() ||
              ((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
   mFlags &= ~aFlags;
-  if (IsValid() && mActor && mActor->CanSend()) {
+  if (IsValid() && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
     mActor->SendRecycleTexture(mFlags);
   }
 }
 
 void
 TextureClient::RecycleTexture(TextureFlags aFlags)
 {
   MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE);
 
   mAddedToCompositableClient = false;
   if (mFlags != aFlags) {
     mFlags = aFlags;
-    if (IsValid() && mActor && mActor->CanSend()) {
+    if (IsValid() && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
       mActor->SendRecycleTexture(mFlags);
     }
   }
 }
 
 void
 TextureClient::WaitForCompositorRecycle()
 {
@@ -719,39 +693,32 @@ TextureClient::SetRecycleAllocator(IText
     ClearRecycleCallback();
   }
 }
 
 bool
 TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
 {
   MOZ_ASSERT(aForwarder && aForwarder->GetMessageLoop() == mAllocator->AsClientAllocator()->GetMessageLoop());
-  if (mActor && !mActor->mTextureClientDestroyed && mActor->GetForwarder() == aForwarder) {
+  if (mActor && !mActor->mDestroyed && mActor->GetForwarder() == aForwarder) {
     return true;
   }
-  MOZ_ASSERT(!mActor || mActor->mTextureClientDestroyed, "Cannot use a texture on several IPC channels.");
+  MOZ_ASSERT(!mActor || mActor->mDestroyed, "Cannot use a texture on several IPC channels.");
 
   SurfaceDescriptor desc;
   if (!ToSurfaceDescriptor(desc)) {
     return false;
   }
 
   mActor = static_cast<TextureChild*>(aForwarder->CreateTexture(desc, aForwarder->GetCompositorBackendType(), GetFlags()));
   MOZ_ASSERT(mActor);
+  mActor->mForwarder = aForwarder;
   mActor->mTextureClient = this;
-  mActor->mForwarder = aForwarder;
-  mActor->mAllocator = mAllocator;
   mActor->mMainThreadOnly = !!(mFlags & TextureFlags::DEALLOCATE_MAIN_THREAD);
-  mActor->mOwnsTextureData = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT);
-  mActor->mSyncDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT);
-  if (!mWorkaroundAnnoyingSharedSurfaceLifetimeIssues) {
-    mActor->mTextureData = mData;
-  }
-
-  return mActor->CanSend();
+  return mActor->IPCOpen();
 }
 
 PTextureChild*
 TextureClient::GetIPDLActor()
 {
   return mActor;
 }
 
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -423,19 +423,17 @@ public:
    * Allocate and deallocate a TextureChild actor.
    *
    * TextureChild is an implementation detail of TextureClient that is not
    * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
    * are for use with the managing IPDL protocols only (so that they can
    * implement AllocPextureChild and DeallocPTextureChild).
    */
   static PTextureChild* CreateIPDLActor();
-  static bool DeallocIPDLActor(PTextureChild* actor);
-  static void ForceIPDLActorShutdown(PTextureChild* actor,
-                                     const char* const aProtocolName);
+  static bool DestroyIPDLActor(PTextureChild* actor);
   // call this if the transaction that was supposed to destroy the actor failed.
   static bool DestroyFallback(PTextureChild* actor);
 
   /**
    * Get the TextureClient corresponding to the actor passed in parameter.
    */
   static TextureClient* AsTextureClient(PTextureChild* actor);
 
@@ -617,17 +615,17 @@ protected:
    * Calling ToSurfaceDescriptor again after it has already returned true,
    * or never constructing a TextureHost with aDescriptor may result in a memory
    * leak (see TextureClientD3D9 for example).
    */
   bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor);
 
 
   RefPtr<ClientIPCAllocator> mAllocator;
-  TextureChild* mActor;
+  RefPtr<TextureChild> mActor;
   RefPtr<ITextureClientRecycleAllocator> mRecycleAllocator;
   RefPtr<AsyncTransactionWaiter> mRemoveFromCompositableWaiter;
 
   TextureData* mData;
   RefPtr<gfx::DrawTarget> mBorrowedDrawTarget;
 
   TextureFlags mFlags;
   FenceHandle mReleaseFenceHandle;
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -262,22 +262,28 @@ static void ImageBridgeShutdownStep1(Ree
 
   MediaSystemResourceManager::Shutdown();
 
   if (sImageBridgeChildSingleton) {
     // Force all managed protocols to shut themselves down cleanly
     InfallibleTArray<PCompositableChild*> compositables;
     sImageBridgeChildSingleton->ManagedPCompositableChild(compositables);
     for (int i = compositables.Length() - 1; i >= 0; --i) {
-      CompositableClient::ForceIPDLActorShutdown(compositables[i], "ImageBridge");
+      auto compositable = CompositableClient::FromIPDLActor(compositables[i]);
+      if (compositable) {
+        compositable->Destroy();
+      }
     }
     InfallibleTArray<PTextureChild*> textures;
     sImageBridgeChildSingleton->ManagedPTextureChild(textures);
     for (int i = textures.Length() - 1; i >= 0; --i) {
-      TextureClient::ForceIPDLActorShutdown(textures[i], "ImageBridge");
+      RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]);
+      if (client) {
+        client->Destroy();
+      }
     }
     sImageBridgeChildSingleton->FallbackDestroyActors();
 
     sImageBridgeChildSingleton->SendWillClose();
     sImageBridgeChildSingleton->MarkShutDown();
     // From now on, no message can be sent through the image bridge from the
     // client side except the final Stop message.
   }
@@ -386,17 +392,17 @@ ImageBridgeChild::AllocPCompositableChil
 {
   MOZ_ASSERT(!mShuttingDown);
   return CompositableClient::CreateIPDLActor();
 }
 
 bool
 ImageBridgeChild::DeallocPCompositableChild(PCompositableChild* aActor)
 {
-  return CompositableClient::DeallocIPDLActor(aActor);
+  return CompositableClient::DestroyIPDLActor(aActor);
 }
 
 
 Thread* ImageBridgeChild::GetThread() const
 {
   return sImageBridgeChildThread;
 }
 
@@ -462,16 +468,17 @@ void ImageBridgeChild::DispatchReleaseIm
 
   if (!IsCreated()) {
     if (aClient) {
       // CompositableClient::Release should normally happen in the ImageBridgeChild
       // thread because it usually generate some IPDL messages.
       // However, if we take this branch it means that the ImageBridgeChild
       // has already shut down, along with the CompositableChild, which means no
       // message will be sent and it is safe to run this code from any thread.
+      MOZ_ASSERT(aClient->GetIPDLActor() == nullptr);
       aClient->Release();
     }
     delete aChild;
     return;
   }
 
   sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
     FROM_HERE,
@@ -492,16 +499,17 @@ void ImageBridgeChild::DispatchReleaseCa
   }
 
   if (!IsCreated()) {
     // CompositableClient::Release should normally happen in the ImageBridgeChild
     // thread because it usually generate some IPDL messages.
     // However, if we take this branch it means that the ImageBridgeChild
     // has already shut down, along with the CompositableChild, which means no
     // message will be sent and it is safe to run this code from any thread.
+    MOZ_ASSERT(aClient->GetIPDLActor() == nullptr);
     aClient->Release();
     return;
   }
 
   sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
     FROM_HERE,
     NewRunnableFunction(&ReleaseCanvasClientNow, aClient));
 }
@@ -520,16 +528,17 @@ void ImageBridgeChild::DispatchReleaseTe
   }
 
   if (!IsCreated()) {
     // TextureClient::Release should normally happen in the ImageBridgeChild
     // thread because it usually generate some IPDL messages.
     // However, if we take this branch it means that the ImageBridgeChild
     // has already shut down, along with the TextureChild, which means no
     // message will be sent and it is safe to run this code from any thread.
+    MOZ_ASSERT(aClient->GetIPDLActor() == nullptr);
     RELEASE_MANUALLY(aClient);
     return;
   }
 
   sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
     FROM_HERE,
     NewRunnableFunction(&ReleaseTextureClientNow, aClient));
 }
@@ -1087,17 +1096,17 @@ ImageBridgeChild::AllocPTextureChild(con
 {
   MOZ_ASSERT(!mShuttingDown);
   return TextureClient::CreateIPDLActor();
 }
 
 bool
 ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor)
 {
-  return TextureClient::DeallocIPDLActor(actor);
+  return TextureClient::DestroyIPDLActor(actor);
 }
 
 PMediaSystemResourceManagerChild*
 ImageBridgeChild::AllocPMediaSystemResourceManagerChild()
 {
   MOZ_ASSERT(!mShuttingDown);
   return new mozilla::media::MediaSystemResourceManagerChild();
 }
--- a/gfx/layers/ipc/LayerTransactionChild.cpp
+++ b/gfx/layers/ipc/LayerTransactionChild.cpp
@@ -32,24 +32,26 @@ LayerTransactionChild::Destroy()
   // under Send__delete__() call, this function is called from
   // ShadowLayerForwarder's destructor.
   // When it happens, IPCOpen() is still true.
   // See bug 1004191.
   mDestroyed = true;
   MOZ_ASSERT(0 == ManagedPLayerChild().Count(),
              "layers should have been cleaned up by now");
 
-  const ManagedContainer<PCompositableChild>& compositables = ManagedPCompositableChild();
-  for (auto iter = compositables.ConstIter(); !iter.Done(); iter.Next()) {
-    CompositableClient::ForceIPDLActorShutdown(iter.Get()->GetKey(), "CompositorBridge");
-  }
-
   const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild();
   for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) {
-    TextureClient::ForceIPDLActorShutdown(iter.Get()->GetKey(), "CompositorBridge");
+    TextureClient* texture = TextureClient::AsTextureClient(iter.Get()->GetKey());
+
+    if (texture) {
+      // TODO: cf bug 1242448.
+      //gfxDevCrash(gfx::LogReason::TextureAliveAfterShutdown)
+      //  << "A texture is held alive after shutdown (PCompositorBridge)";
+      texture->Destroy();
+    }
   }
 
   SendShutdown();
 }
 
 
 PLayerChild*
 LayerTransactionChild::AllocPLayerChild()
@@ -71,17 +73,17 @@ LayerTransactionChild::AllocPCompositabl
 {
   MOZ_ASSERT(!mDestroyed);
   return CompositableClient::CreateIPDLActor();
 }
 
 bool
 LayerTransactionChild::DeallocPCompositableChild(PCompositableChild* actor)
 {
-  return CompositableClient::DeallocIPDLActor(actor);
+  return CompositableClient::DestroyIPDLActor(actor);
 }
 
 bool
 LayerTransactionChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages)
 {
   for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
     const AsyncParentMessageData& message = aMessages[i];
 
@@ -135,13 +137,13 @@ LayerTransactionChild::AllocPTextureChil
 {
   MOZ_ASSERT(!mDestroyed);
   return TextureClient::CreateIPDLActor();
 }
 
 bool
 LayerTransactionChild::DeallocPTextureChild(PTextureChild* actor)
 {
-  return TextureClient::DeallocIPDLActor(actor);
+  return TextureClient::DestroyIPDLActor(actor);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -859,25 +859,25 @@ gfxPlatform::InitLayersIPC()
     {
         mozilla::layers::CompositorBridgeParent::StartUp();
 #ifdef MOZ_WIDGET_GONK
         SharedBufferManagerChild::StartUp();
 #endif
         mozilla::layers::ImageBridgeChild::StartUp();
         gfx::VRManagerChild::StartUpSameProcess();
     }
-
 }
 
 /* static */ void
 gfxPlatform::ShutdownLayersIPC()
 {
     if (!sLayersIPCIsUp) {
       return;
     }
+    sLayersIPCIsUp = false;
 
     if (XRE_IsContentProcess()) {
 
         gfx::VRManagerChild::ShutDown();
         // cf bug 1215265.
         if (gfxPrefs::ChildProcessShutdown()) {
           layers::ImageBridgeChild::ShutDown();
           layers::CompositorBridgeChild::ShutDown();
@@ -894,24 +894,16 @@ gfxPlatform::ShutdownLayersIPC()
 #endif
 
         // This has to happen after shutting down the child protocols.
         layers::CompositorBridgeParent::ShutDown();
     } else {
       // TODO: There are other kind of processes and we should make sure gfx
       // stuff is either not created there or shut down properly.
     }
-
-    sLayersIPCIsUp = false;
-}
-
-// static
-bool gfxPlatform::IPCAlreadyShutDown()
-{
-  return !sLayersIPCIsUp;
 }
 
 gfxPlatform::~gfxPlatform()
 {
     mScreenReferenceSurface = nullptr;
     mScreenReferenceDrawTarget = nullptr;
 
     // The cairo folks think we should only clean up in debug builds,
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -168,17 +168,16 @@ public:
     /**
      * Shut down Thebes.
      * Init() arranges for this to be called at an appropriate time.
      */
     static void Shutdown();
 
     static void InitLayersIPC();
     static void ShutdownLayersIPC();
-    static bool IPCAlreadyShutDown();
 
     /**
      * Create an offscreen surface of the given dimensions
      * and image format.
      */
     virtual already_AddRefed<gfxASurface>
       CreateOffscreenSurface(const IntSize& aSize,
                              gfxImageFormat aFormat) = 0;