diff --git a/ipc/glue/BackgroundImpl.cpp b/ipc/glue/BackgroundImpl.cpp
index 8c498f1b9b52340a9172f5ff4534ef3967dd9d40..f3e987031301ede37c6f17ca69862d7af70a1809 100644
--- a/ipc/glue/BackgroundImpl.cpp
+++ b/ipc/glue/BackgroundImpl.cpp
@@ -35,6 +35,12 @@
 #include "nsXPCOMPrivate.h"
 #include "prthread.h"
 
+#ifdef RELEASE_BUILD
+#define THREADSAFETY_ASSERT MOZ_ASSERT
+#else
+#define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
+#endif
+
 #define CRASH_IN_CHILD_PROCESS(_msg)                                           \
   do {                                                                         \
     if (IsMainProcess()) {                                                     \
@@ -86,7 +92,7 @@ AssertIsInChildProcess()
 void
 AssertIsOnMainThread()
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  THREADSAFETY_ASSERT(NS_IsMainThread());
 }
 
 // -----------------------------------------------------------------------------
@@ -174,10 +180,18 @@ private:
   // deleting it on the wrong thread. Only non-null for other-process actors.
   Transport* mTransport;
 
+  // Set when the actor is opened successfully and used to handle shutdown
+  // hangs. Only touched on the background thread.
   nsTArray<ParentImpl*>* mLiveActorArray;
 
-  // Used to assert things in DEBUG builds.
-  DebugOnly<bool> mIsOtherProcessActorDEBUG;
+  // Set at construction to indicate whether this parent actor corresponds to a
+  // child actor in another process or to a child actor from a different thread
+  // in the same process.
+  const bool mIsOtherProcessActor;
+
+  // Set after ActorDestroy has been called. Only touched on the background
+  // thread.
+  bool mActorDestroyed;
 
 public:
   static bool
@@ -192,7 +206,7 @@ public:
   static void
   AssertIsOnBackgroundThread()
   {
-    MOZ_ASSERT(IsOnBackgroundThread());
+    THREADSAFETY_ASSERT(IsOnBackgroundThread());
   }
 
   NS_INLINE_DECL_REFCOUNTING(ParentImpl)
@@ -201,6 +215,14 @@ public:
   Destroy();
 
 private:
+  // Forwarded from BackgroundParent.
+  static bool
+  IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
+
+  // Forwarded from BackgroundParent.
+  static already_AddRefed<ContentParent>
+  GetContentParent(PBackgroundParent* aBackgroundActor);
+
   // Forwarded from BackgroundParent.
   static PBackgroundParent*
   Alloc(ContentParent* aContent,
@@ -218,8 +240,8 @@ private:
 
   // For same-process actors.
   ParentImpl()
-  : mTransport(nullptr), mLiveActorArray(nullptr),
-    mIsOtherProcessActorDEBUG(false)
+  : mTransport(nullptr), mLiveActorArray(nullptr), mIsOtherProcessActor(false),
+    mActorDestroyed(false)
   {
     AssertIsInMainProcess();
     AssertIsOnMainThread();
@@ -230,7 +252,7 @@ private:
   // For other-process actors.
   ParentImpl(ContentParent* aContent, Transport* aTransport)
   : mContent(aContent), mTransport(aTransport), mLiveActorArray(nullptr),
-    mIsOtherProcessActorDEBUG(true)
+    mIsOtherProcessActor(true), mActorDestroyed(false)
   {
     AssertIsInMainProcess();
     AssertIsOnMainThread();
@@ -257,7 +279,7 @@ private:
     MOZ_ASSERT(aLiveActorArray);
     MOZ_ASSERT(!aLiveActorArray->Contains(this));
     MOZ_ASSERT(!mLiveActorArray);
-    MOZ_ASSERT(mIsOtherProcessActorDEBUG);
+    MOZ_ASSERT(mIsOtherProcessActor);
 
     mLiveActorArray = aLiveActorArray;
     mLiveActorArray->AppendElement(this);
@@ -318,7 +340,11 @@ class ChildImpl MOZ_FINAL : public BackgroundChildImpl
   // create the background thread after application shutdown has started.
   static bool sShutdownHasStarted;
 
+#ifdef RELEASE_BUILD
   DebugOnly<nsIThread*> mBoundThread;
+#else
+  nsIThread* mBoundThread;
+#endif
 
 public:
   static bool
@@ -330,15 +356,18 @@ public:
   void
   AssertIsOnBoundThread()
   {
-    MOZ_ASSERT(mBoundThread);
+    THREADSAFETY_ASSERT(mBoundThread);
 
+#ifdef RELEASE_BUILD
     DebugOnly<bool> current;
-    MOZ_ASSERT(NS_SUCCEEDED(mBoundThread->IsOnCurrentThread(&current)));
-
-    MOZ_ASSERT(current);
+#else
+    bool current;
+#endif
+    THREADSAFETY_ASSERT(
+      NS_SUCCEEDED(mBoundThread->IsOnCurrentThread(&current)));
+    THREADSAFETY_ASSERT(current);
   }
 
-
   ChildImpl()
   : mBoundThread(nullptr)
   {
@@ -387,11 +416,13 @@ private:
   void
   SetBoundThread()
   {
-#ifdef DEBUG
-    MOZ_ASSERT(!mBoundThread);
+    THREADSAFETY_ASSERT(!mBoundThread);
+
+#if defined(DEBUG) || !defined(RELEASE_BUILD)
     mBoundThread = NS_GetCurrentThread();
-    MOZ_ASSERT(mBoundThread);
 #endif
+
+    THREADSAFETY_ASSERT(mBoundThread);
   }
 
   // Only called by IPDL.
@@ -740,6 +771,20 @@ AssertIsOnBackgroundThread()
 // BackgroundParent Public Methods
 // -----------------------------------------------------------------------------
 
+// static
+bool
+BackgroundParent::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
+{
+  return ParentImpl::IsOtherProcessActor(aBackgroundActor);
+}
+
+// static
+already_AddRefed<ContentParent>
+BackgroundParent::GetContentParent(PBackgroundParent* aBackgroundActor)
+{
+  return ParentImpl::GetContentParent(aBackgroundActor);
+}
+
 // static
 PBackgroundParent*
 BackgroundParent::Alloc(ContentParent* aContent,
@@ -826,6 +871,46 @@ bool ChildImpl::sShutdownHasStarted = false;
 // ParentImpl Implementation
 // -----------------------------------------------------------------------------
 
+// static
+bool
+ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aBackgroundActor);
+
+  return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
+}
+
+// static
+already_AddRefed<ContentParent>
+ParentImpl::GetContentParent(PBackgroundParent* aBackgroundActor)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aBackgroundActor);
+
+  auto actor = static_cast<ParentImpl*>(aBackgroundActor);
+  if (actor->mActorDestroyed) {
+    MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
+    return nullptr;
+  }
+
+  if (actor->mContent) {
+    // We need to hand out a reference to our ContentParent but we also need to
+    // keep the one we have. We can't call AddRef here because ContentParent is
+    // not threadsafe so instead we dispatch a runnable to the main thread to do
+    // it for us. This is safe since we are guaranteed that our AddRef runnable
+    // will run before the reference we hand out can be released, and the
+    // ContentParent can't die as long as the existing reference is maintained.
+    nsCOMPtr<nsIRunnable> runnable =
+      NS_NewNonOwningRunnableMethod(actor->mContent, &ContentParent::AddRef);
+    MOZ_ASSERT(runnable);
+
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
+  }
+
+  return actor->mContent.get();
+}
+
 // static
 PBackgroundParent*
 ParentImpl::Alloc(ContentParent* aContent,
@@ -1095,10 +1180,10 @@ ParentImpl::MainThreadActorDestroy()
 {
   AssertIsInMainProcess();
   AssertIsOnMainThread();
-  MOZ_ASSERT_IF(mIsOtherProcessActorDEBUG, mContent);
-  MOZ_ASSERT_IF(!mIsOtherProcessActorDEBUG, !mContent);
-  MOZ_ASSERT_IF(mIsOtherProcessActorDEBUG, mTransport);
-  MOZ_ASSERT_IF(!mIsOtherProcessActorDEBUG, !mTransport);
+  MOZ_ASSERT_IF(mIsOtherProcessActor, mContent);
+  MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
+  MOZ_ASSERT_IF(mIsOtherProcessActor, mTransport);
+  MOZ_ASSERT_IF(!mIsOtherProcessActor, !mTransport);
 
   if (mTransport) {
     XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
@@ -1167,10 +1252,13 @@ ParentImpl::ActorDestroy(ActorDestroyReason aWhy)
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
-  MOZ_ASSERT_IF(mIsOtherProcessActorDEBUG, mLiveActorArray);
+  MOZ_ASSERT(!mActorDestroyed);
+  MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray);
 
   BackgroundParentImpl::ActorDestroy(aWhy);
 
+  mActorDestroyed = true;
+
   if (mLiveActorArray) {
     MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
     mLiveActorArray = nullptr;
diff --git a/ipc/glue/BackgroundParent.h b/ipc/glue/BackgroundParent.h
index 6e47ae0d9d94bab3d7a5224127dcf88d1c99ff5d..615e34dbc4d49c027837fceccc9279c687912233 100644
--- a/ipc/glue/BackgroundParent.h
+++ b/ipc/glue/BackgroundParent.h
@@ -9,6 +9,8 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/ipc/Transport.h"
 
+template <class> class already_AddRefed;
+
 namespace mozilla {
 namespace dom {
 
@@ -20,8 +22,8 @@ namespace ipc {
 
 class PBackgroundParent;
 
-// This class is not designed for public consumption. It must only be used by
-// ContentParent.
+// This class is not designed for public consumption beyond the few static
+// member functions.
 class BackgroundParent MOZ_FINAL
 {
   friend class mozilla::dom::ContentParent;
@@ -30,6 +32,25 @@ class BackgroundParent MOZ_FINAL
   typedef mozilla::dom::ContentParent ContentParent;
   typedef mozilla::ipc::Transport Transport;
 
+public:
+  // This function allows the caller to determine if the given parent actor
+  // corresponds to a child actor from another process or a child actor from a
+  // different thread in the same process.
+  // This function may only be called on the background thread.
+  static bool
+  IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
+
+  // This function returns the ContentParent associated with the parent actor if
+  // the parent actor corresponds to a child actor from another process. If the
+  // parent actor corresponds to a child actor from a different thread in the
+  // same process then this function returns null.
+  // This function may only be called on the background thread. However,
+  // ContentParent is not threadsafe and the returned pointer may not be used on
+  // any thread other than the main thread. Callers must take care to use (and
+  // release) the returned pointer appropriately.
+  static already_AddRefed<ContentParent>
+  GetContentParent(PBackgroundParent* aBackgroundActor);
+
 private:
   // Only called by ContentParent for cross-process actors.
   static PBackgroundParent*