Merge inbound to mozilla-central a=merge
authordluca <dluca@mozilla.com>
Thu, 09 Nov 2017 15:56:43 +0200
changeset 695600 2bdf6eed0f64a51dfe099e089852533595f1a896
parent 695599 05ae89bebb64438b208ce4daadadc8574b238171 (current diff)
parent 695552 176a739c66b9ebd4098131339c0ed12a192c7dc9 (diff)
child 695601 c2837ae3bc397a02e3a0d3c53135c46830a42b40
child 695617 779051310af416ffb6416e00e98d2ffc17a35d54
child 695618 157115ace63643fb69df9ff77a949533f660f7d9
child 695619 486620c2345ab558d0507c14a19e49f631b8347f
child 695695 bc75858996d073022d8edaeb259cd2a274fa7951
child 695696 2f1c4fe1d278d3db12ee99610c6db804a92ae864
child 695698 d04c28d9269ef9428ac794d9d9a15049395ac0e7
child 695699 b950688bd08a0b491baf863ea196dcf7e360ce2c
child 695703 dca383e5f5b770fa3adb09d753897633258302a1
child 695713 cbb9106c4b942c483c34c43bab8c2a965117fb75
child 695714 126d13548cc4bcdbfcd0aa1b35330aa35c0056e2
child 695715 ba13075761914e1a198aeb4381b3510c495ef81e
child 695721 747c5e016f050cf656bb7f3105e4cc7dcb254df3
child 695729 42f6dd3fc713a7edede0def4bc2adaba0ac5d6bd
child 695744 62ebcfb7b5324457d41f49f54706f621a1cd5366
child 695756 41d667952cf2ce3f3945577c9e5d10b0be44ef60
child 695766 9aff6ae3fc566b7cb599b63b53350069801d83b5
child 695795 b7649785bd6360f6b5b9ab4405dafeaf25d31324
child 695804 c401beee9edef52607f71e3d904c4622ebedaac9
child 695806 dcd35dcddec7594f165f1fdd6f9f288745e2edf3
child 695822 b83bf81ee8fae073420adf6d3ecdaa4a71da08e4
child 695837 a04612813ad0d00ecb0a0c4aede3523d1de14409
child 695869 4fe9a9993e1b70550410cd6b79729535160bebe5
child 695895 25b077ce0dc9115c87fbb7c0f30b2b3c453be895
child 695896 9a70cf4cc15109eda51c203d2194decc1366dce2
child 695897 7cad04fef22441705384677e79ead832e123c9e7
child 695942 4c9771547b0f288a637af8878683297f1eceedc1
child 696051 0d1e421a0c68cca305ff420b3bd805e330195266
child 696075 f767d15056cb5d1f101099463ca21cd89af4ed85
child 696460 cda651f093a2a78da2f42d4ea5a4dbb06ea90c64
child 696503 3f13418cda362b3928095de29ba021c4d0ea2098
child 696820 8de3502850a1efe4e5da71b68253c1a3f8e3a49a
child 696821 869b104c8cbaca2723173fea4e505d01b4d6bae7
child 697301 9dc44476eda38c5abe419cc11396c837b0668b83
child 697305 3dece9b7c9b08d8cccf6cb8684d79788034aac01
child 697421 cde080797667a0c8e5e06e94a05d3ca55fa0f698
child 697965 c91550e48eba092ea14923dccd2b8e60f077b4f3
child 699073 cef32157a9a99835c0412c27be2a77dd1ff4adcd
child 699755 e9747f4678969aa5cdd779d42a98fb558b6d39e2
push id88473
push userkgupta@mozilla.com
push dateThu, 09 Nov 2017 14:05:50 +0000
reviewersmerge
milestone58.0a1
Merge inbound to mozilla-central a=merge
js/src/wasm/WasmJS.cpp
new file mode 100644
--- /dev/null
+++ b/dom/clients/manager/ClientHandle.cpp
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "ClientHandle.h"
+
+#include "ClientHandleChild.h"
+#include "ClientHandleOpChild.h"
+#include "ClientManager.h"
+#include "mozilla/dom/PClientManagerChild.h"
+
+namespace mozilla {
+namespace dom {
+
+ClientHandle::~ClientHandle()
+{
+  Shutdown();
+}
+
+void
+ClientHandle::Shutdown()
+{
+  NS_ASSERT_OWNINGTHREAD(ClientSource);
+  if (IsShutdown()) {
+    return;
+  }
+
+  ShutdownThing();
+
+  mManager = nullptr;
+}
+
+already_AddRefed<ClientOpPromise>
+ClientHandle::StartOp(const ClientOpConstructorArgs& aArgs)
+{
+  RefPtr<ClientOpPromise::Private> promise =
+    new ClientOpPromise::Private(__func__);
+
+  // Hold a ref to the client until the remote operation completes.  Otherwise
+  // the ClientHandle might get de-refed and teardown the actor before we
+  // get an answer.
+  RefPtr<ClientHandle> kungFuGrip = this;
+  promise->Then(mSerialEventTarget, __func__,
+                [kungFuGrip] (const ClientOpResult &) { },
+                [kungFuGrip] (nsresult) { });
+
+  MaybeExecute([aArgs, promise] (ClientHandleChild* aActor) {
+    ClientHandleOpChild* actor = new ClientHandleOpChild(aArgs, promise);
+    if (!aActor->SendPClientHandleOpConstructor(actor, aArgs)) {
+      // Constructor failure will reject promise via ActorDestroy()
+      return;
+    }
+  });
+
+  RefPtr<ClientOpPromise> ref = promise.get();
+  return ref.forget();
+}
+
+ClientHandle::ClientHandle(ClientManager* aManager,
+                           nsISerialEventTarget* aSerialEventTarget,
+                           const ClientInfo& aClientInfo)
+  : mManager(aManager)
+  , mSerialEventTarget(aSerialEventTarget)
+  , mClientInfo(aClientInfo)
+{
+  MOZ_DIAGNOSTIC_ASSERT(mManager);
+  MOZ_DIAGNOSTIC_ASSERT(mSerialEventTarget);
+  MOZ_ASSERT(mSerialEventTarget->IsOnCurrentThread());
+}
+
+void
+ClientHandle::Activate(PClientManagerChild* aActor)
+{
+  NS_ASSERT_OWNINGTHREAD(ClientHandle);
+
+  if (IsShutdown()) {
+    return;
+  }
+
+  PClientHandleChild* actor =
+    aActor->SendPClientHandleConstructor(mClientInfo.ToIPC());
+  if (!actor) {
+    Shutdown();
+    return;
+  }
+
+  ActivateThing(static_cast<ClientHandleChild*>(actor));
+}
+
+const ClientInfo&
+ClientHandle::Info() const
+{
+  return mClientInfo;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/clients/manager/ClientHandle.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 _mozilla_dom_ClientHandle_h
+#define _mozilla_dom_ClientHandle_h
+
+#include "mozilla/dom/ClientInfo.h"
+#include "mozilla/dom/ClientOpPromise.h"
+#include "mozilla/dom/ClientThing.h"
+
+#ifdef XP_WIN
+#undef PostMessage
+#endif
+
+namespace mozilla {
+
+namespace dom {
+
+class ClientManager;
+class ClientHandleChild;
+class ClientOpConstructorArgs;
+class PClientManagerChild;
+
+// The ClientHandle allows code to take a simple ClientInfo struct and
+// convert it into a live actor-backed object attached to a particular
+// ClientSource somewhere in the browser.  If the ClientSource is
+// destroyed then the ClientHandle will simply begin to reject operations.
+// We do not currently provide a way to be notified when the ClientSource
+// is destroyed, but this could be added in the future.
+class ClientHandle final : public ClientThing<ClientHandleChild>
+{
+  friend class ClientManager;
+
+  RefPtr<ClientManager> mManager;
+  nsCOMPtr<nsISerialEventTarget> mSerialEventTarget;
+  ClientInfo mClientInfo;
+
+  ~ClientHandle();
+
+  void
+  Shutdown();
+
+  already_AddRefed<ClientOpPromise>
+  StartOp(const ClientOpConstructorArgs& aArgs);
+
+  // Private methods called by ClientManager
+  ClientHandle(ClientManager* aManager,
+               nsISerialEventTarget* aSerialEventTarget,
+               const ClientInfo& aClientInfo);
+
+  void
+  Activate(PClientManagerChild* aActor);
+
+public:
+  const ClientInfo&
+  Info() const;
+
+  NS_INLINE_DECL_REFCOUNTING(ClientHandle);
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // _mozilla_dom_ClientHandle_h
--- a/dom/clients/manager/ClientHandleParent.cpp
+++ b/dom/clients/manager/ClientHandleParent.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "ClientHandleParent.h"
 
 #include "ClientHandleOpParent.h"
+#include "ClientManagerService.h"
 #include "ClientSourceParent.h"
 #include "mozilla/dom/ClientIPCTypes.h"
 #include "mozilla/Unused.h"
 
 namespace mozilla {
 namespace dom {
 
 using mozilla::ipc::IPCResult;
@@ -21,16 +22,20 @@ ClientHandleParent::RecvTeardown()
 {
   Unused << Send__delete__(this);
   return IPC_OK();
 }
 
 void
 ClientHandleParent::ActorDestroy(ActorDestroyReason aReason)
 {
+  if (mSource) {
+    mSource->DetachHandle(this);
+    mSource = nullptr;
+  }
 }
 
 PClientHandleOpParent*
 ClientHandleParent::AllocPClientHandleOpParent(const ClientOpConstructorArgs& aArgs)
 {
   return new ClientHandleOpParent();
 }
 
@@ -46,22 +51,38 @@ ClientHandleParent::RecvPClientHandleOpC
                                                    const ClientOpConstructorArgs& aArgs)
 {
   auto actor = static_cast<ClientHandleOpParent*>(aActor);
   actor->Init(aArgs);
   return IPC_OK();
 }
 
 ClientHandleParent::ClientHandleParent()
+  : mService(ClientManagerService::GetOrCreateInstance())
+  , mSource(nullptr)
 {
 }
 
 ClientHandleParent::~ClientHandleParent()
 {
+  MOZ_DIAGNOSTIC_ASSERT(!mSource);
 }
 
 void
 ClientHandleParent::Init(const IPCClientInfo& aClientInfo)
 {
+  mSource = mService->FindSource(aClientInfo.id(), aClientInfo.principalInfo());
+  if (!mSource) {
+    Unused << Send__delete__(this);
+    return;
+  }
+
+  mSource->AttachHandle(this);
+}
+
+ClientSourceParent*
+ClientHandleParent::GetSource() const
+{
+  return mSource;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientHandleParent.h
+++ b/dom/clients/manager/ClientHandleParent.h
@@ -6,18 +6,24 @@
 #ifndef _mozilla_dom_ClientHandleParent_h
 #define _mozilla_dom_ClientHandleParent_h
 
 #include "mozilla/dom/PClientHandleParent.h"
 
 namespace mozilla {
 namespace dom {
 
+class ClientManagerService;
+class ClientSourceParent;
+
 class ClientHandleParent final : public PClientHandleParent
 {
+  RefPtr<ClientManagerService> mService;
+  ClientSourceParent* mSource;
+
   // PClientHandleParent interface
   mozilla::ipc::IPCResult
   RecvTeardown() override;
 
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
   PClientHandleOpParent*
@@ -31,14 +37,17 @@ class ClientHandleParent final : public 
                                  const ClientOpConstructorArgs& aArgs) override;
 
 public:
   ClientHandleParent();
   ~ClientHandleParent();
 
   void
   Init(const IPCClientInfo& aClientInfo);
+
+  ClientSourceParent*
+  GetSource() const;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientHandleParent_h
--- a/dom/clients/manager/ClientIPCTypes.ipdlh
+++ b/dom/clients/manager/ClientIPCTypes.ipdlh
@@ -12,16 +12,20 @@ using ClientType from "mozilla/dom/Clien
 using FrameType from "mozilla/dom/ClientIPCUtils.h";
 using VisibilityState from "mozilla/dom/ClientIPCUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 struct ClientSourceConstructorArgs
 {
+  nsID id;
+  ClientType type;
+  PrincipalInfo principalInfo;
+  TimeStamp creationTime;
 };
 
 struct IPCClientInfo
 {
   nsID id;
   ClientType type;
   PrincipalInfo principalInfo;
   TimeStamp creationTime;
new file mode 100644
--- /dev/null
+++ b/dom/clients/manager/ClientManager.cpp
@@ -0,0 +1,236 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "ClientManager.h"
+
+#include "ClientHandle.h"
+#include "ClientManagerChild.h"
+#include "ClientManagerOpChild.h"
+#include "ClientSource.h"
+#include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/dom/workers/bindings/WorkerHolderToken.h"
+#include "mozilla/ipc/BackgroundChild.h"
+#include "mozilla/ipc/PBackgroundChild.h"
+#include "prthread.h"
+
+namespace mozilla {
+namespace dom {
+
+using mozilla::ipc::BackgroundChild;
+using mozilla::ipc::PBackgroundChild;
+using mozilla::ipc::PrincipalInfo;
+using mozilla::dom::workers::Closing;
+using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
+using mozilla::dom::workers::WorkerHolderToken;
+using mozilla::dom::workers::WorkerPrivate;
+
+namespace {
+
+uint32_t kBadThreadLocalIndex = -1;
+uint32_t sClientManagerThreadLocalIndex = kBadThreadLocalIndex;
+
+} // anonymous namespace
+
+ClientManager::ClientManager()
+{
+  PBackgroundChild* parentActor = BackgroundChild::GetOrCreateForCurrentThread();
+  if (NS_WARN_IF(!parentActor)) {
+    Shutdown();
+    return;
+  }
+
+  RefPtr<WorkerHolderToken> workerHolderToken;
+  if (!NS_IsMainThread()) {
+    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+    MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
+
+    workerHolderToken =
+      WorkerHolderToken::Create(workerPrivate, Closing,
+                                WorkerHolderToken::AllowIdleShutdownStart);
+    if (NS_WARN_IF(!workerHolderToken)) {
+      Shutdown();
+      return;
+    }
+  }
+
+  ClientManagerChild* actor = new ClientManagerChild(workerHolderToken);
+  PClientManagerChild *sentActor =
+    parentActor->SendPClientManagerConstructor(actor);
+  if (NS_WARN_IF(!sentActor)) {
+    Shutdown();
+    return;
+  }
+  MOZ_DIAGNOSTIC_ASSERT(sentActor == actor);
+
+  ActivateThing(actor);
+}
+
+ClientManager::~ClientManager()
+{
+  NS_ASSERT_OWNINGTHREAD(ClientManager);
+
+  Shutdown();
+
+  MOZ_DIAGNOSTIC_ASSERT(this == PR_GetThreadPrivate(sClientManagerThreadLocalIndex));
+  PRStatus status =
+    PR_SetThreadPrivate(sClientManagerThreadLocalIndex, nullptr);
+  MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
+}
+
+void
+ClientManager::Shutdown()
+{
+  NS_ASSERT_OWNINGTHREAD(ClientManager);
+
+  if (IsShutdown()) {
+    return;
+  }
+
+  ShutdownThing();
+}
+
+UniquePtr<ClientSource>
+ClientManager::CreateSourceInternal(ClientType aType,
+                                    const PrincipalInfo& aPrincipal)
+{
+  NS_ASSERT_OWNINGTHREAD(ClientManager);
+
+  if (IsShutdown()) {
+    return nullptr;
+  }
+
+  nsID id;
+  nsresult rv = nsContentUtils::GenerateUUIDInPlace(id);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  ClientSourceConstructorArgs args(id, aType, aPrincipal, TimeStamp::Now());
+  UniquePtr<ClientSource> source(new ClientSource(this, args));
+  source->Activate(GetActor());
+
+  return Move(source);
+}
+
+already_AddRefed<ClientHandle>
+ClientManager::CreateHandleInternal(const ClientInfo& aClientInfo,
+                                    nsISerialEventTarget* aSerialEventTarget)
+{
+  NS_ASSERT_OWNINGTHREAD(ClientManager);
+  MOZ_DIAGNOSTIC_ASSERT(aSerialEventTarget);
+
+  if (IsShutdown()) {
+    return nullptr;
+  }
+
+  RefPtr<ClientHandle> handle = new ClientHandle(this, aSerialEventTarget,
+                                                 aClientInfo);
+  handle->Activate(GetActor());
+
+  return handle.forget();
+}
+
+already_AddRefed<ClientOpPromise>
+ClientManager::StartOp(const ClientOpConstructorArgs& aArgs,
+                       nsISerialEventTarget* aSerialEventTarget)
+{
+  RefPtr<ClientOpPromise::Private> promise =
+    new ClientOpPromise::Private(__func__);
+
+  // Hold a ref to the client until the remote operation completes.  Otherwise
+  // the ClientHandle might get de-refed and teardown the actor before we
+  // get an answer.
+  RefPtr<ClientManager> kungFuGrip = this;
+  promise->Then(aSerialEventTarget, __func__,
+                [kungFuGrip] (const ClientOpResult&) { },
+                [kungFuGrip] (nsresult) { });
+
+  MaybeExecute([aArgs, promise] (ClientManagerChild* aActor) {
+    ClientManagerOpChild* actor = new ClientManagerOpChild(aArgs, promise);
+    if (!aActor->SendPClientManagerOpConstructor(actor, aArgs)) {
+      // Constructor failure will reject promise via ActorDestroy()
+      return;
+    }
+  });
+
+  RefPtr<ClientOpPromise> ref = promise.get();
+  return ref.forget();
+}
+
+// static
+already_AddRefed<ClientManager>
+ClientManager::GetOrCreateForCurrentThread()
+{
+  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex);
+  RefPtr<ClientManager> cm =
+    static_cast<ClientManager*>(PR_GetThreadPrivate(sClientManagerThreadLocalIndex));
+
+  if (!cm) {
+    cm = new ClientManager();
+
+    PRStatus status =
+      PR_SetThreadPrivate(sClientManagerThreadLocalIndex, cm.get());
+    MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
+  }
+
+  MOZ_ASSERT(cm);
+  return cm.forget();
+}
+
+WorkerPrivate*
+ClientManager::GetWorkerPrivate() const
+{
+  NS_ASSERT_OWNINGTHREAD(ClientManager);
+  MOZ_DIAGNOSTIC_ASSERT(GetActor());
+  return GetActor()->GetWorkerPrivate();
+}
+
+// static
+void
+ClientManager::Startup()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  PRStatus status =
+    PR_NewThreadPrivateIndex(&sClientManagerThreadLocalIndex, nullptr);
+  MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
+}
+
+// static
+UniquePtr<ClientSource>
+ClientManager::CreateSource(ClientType aType, nsIPrincipal* aPrincipal)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aPrincipal);
+
+  PrincipalInfo principalInfo;
+  nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
+  return mgr->CreateSourceInternal(aType, principalInfo);
+}
+
+// static
+UniquePtr<ClientSource>
+ClientManager::CreateSource(ClientType aType, const PrincipalInfo& aPrincipal)
+{
+  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
+  return mgr->CreateSourceInternal(aType, aPrincipal);
+}
+
+// static
+already_AddRefed<ClientHandle>
+ClientManager::CreateHandle(const ClientInfo& aClientInfo,
+                            nsISerialEventTarget* aSerialEventTarget)
+{
+  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
+  return mgr->CreateHandleInternal(aClientInfo, aSerialEventTarget);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/clients/manager/ClientManager.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 _mozilla_dom_ClientManager_h
+#define _mozilla_dom_ClientManager_h
+
+#include "mozilla/dom/ClientOpPromise.h"
+#include "mozilla/dom/ClientThing.h"
+
+namespace mozilla {
+namespace ipc {
+class PBackgroundChild;
+} // namespace ipc
+namespace dom {
+
+class ClientHandle;
+class ClientInfo;
+class ClientManagerChild;
+class ClientOpConstructorArgs;
+class ClientSource;
+enum class ClientType : uint8_t;
+
+namespace workers {
+class WorkerPrivate;
+} // workers namespace
+
+// The ClientManager provides a per-thread singleton interface workering
+// with the client subsystem.  It allows globals to create ClientSource
+// objects.  It allows other parts of the system to attach to this globals
+// by creating ClientHandle objects.  The ClientManager also provides
+// methods for querying the list of clients active in the system.
+class ClientManager final : public ClientThing<ClientManagerChild>
+{
+  friend class ClientManagerChild;
+
+  ClientManager();
+  ~ClientManager();
+
+  // Utility method to trigger a shutdown of the ClientManager.  This
+  // is called in various error conditions or when the last reference
+  // is dropped.
+  void
+  Shutdown();
+
+  UniquePtr<ClientSource>
+  CreateSourceInternal(ClientType aType,
+                       const mozilla::ipc::PrincipalInfo& aPrincipal);
+
+  already_AddRefed<ClientHandle>
+  CreateHandleInternal(const ClientInfo& aClientInfo,
+                       nsISerialEventTarget* aSerialEventTarget);
+
+  // Utility method to perform an IPC operation.  This will create a
+  // PClientManagerOp actor tied to a MozPromise.  The promise will
+  // resolve or reject with the result of the remote operation.
+  already_AddRefed<ClientOpPromise>
+  StartOp(const ClientOpConstructorArgs& aArgs,
+          nsISerialEventTarget* aSerialEventTarget);
+
+  // Get or create the TLS singleton.  Currently this is only used
+  // internally and external code indirectly calls it by invoking
+  // static methods.
+  static already_AddRefed<ClientManager>
+  GetOrCreateForCurrentThread();
+
+  // Private methods called by ClientSource
+  mozilla::dom::workers::WorkerPrivate*
+  GetWorkerPrivate() const;
+
+public:
+  // Initialize the ClientManager at process start.  This
+  // does book-keeping like creating a TLS identifier, etc.
+  // This should only be called by process startup code.
+  static void
+  Startup();
+
+  static UniquePtr<ClientSource>
+  CreateSource(ClientType aType, nsIPrincipal* aPrincipal);
+
+  static UniquePtr<ClientSource>
+  CreateSource(ClientType aType, const mozilla::ipc::PrincipalInfo& aPrincipal);
+
+  static already_AddRefed<ClientHandle>
+  CreateHandle(const ClientInfo& aClientInfo,
+               nsISerialEventTarget* aSerialEventTarget);
+
+  NS_INLINE_DECL_REFCOUNTING(mozilla::dom::ClientManager)
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // _mozilla_dom_ClientManager_h
--- a/dom/clients/manager/ClientManagerOpParent.cpp
+++ b/dom/clients/manager/ClientManagerOpParent.cpp
@@ -9,15 +9,21 @@
 namespace mozilla {
 namespace dom {
 
 void
 ClientManagerOpParent::ActorDestroy(ActorDestroyReason aReason)
 {
 }
 
+ClientManagerOpParent::ClientManagerOpParent(ClientManagerService* aService)
+  : mService(aService)
+{
+  MOZ_DIAGNOSTIC_ASSERT(mService);
+}
+
 void
 ClientManagerOpParent::Init(const ClientOpConstructorArgs& aArgs)
 {
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientManagerOpParent.h
+++ b/dom/clients/manager/ClientManagerOpParent.h
@@ -10,22 +10,24 @@
 
 namespace mozilla {
 namespace dom {
 
 class ClientManagerService;
 
 class ClientManagerOpParent final : public PClientManagerOpParent
 {
+  RefPtr<ClientManagerService> mService;
+
   // PClientManagerOpParent interface
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
 public:
-  ClientManagerOpParent() = default;
+  explicit ClientManagerOpParent(ClientManagerService* aService);
   ~ClientManagerOpParent() = default;
 
   void
   Init(const ClientOpConstructorArgs& aArgs);
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientManagerParent.cpp
+++ b/dom/clients/manager/ClientManagerParent.cpp
@@ -3,16 +3,17 @@
 /* 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/. */
 
 #include "ClientManagerParent.h"
 
 #include "ClientHandleParent.h"
 #include "ClientManagerOpParent.h"
+#include "ClientManagerService.h"
 #include "ClientSourceParent.h"
 #include "mozilla/dom/PClientNavigateOpParent.h"
 #include "mozilla/Unused.h"
 
 namespace mozilla {
 namespace dom {
 
 using mozilla::ipc::IPCResult;
@@ -49,17 +50,17 @@ ClientManagerParent::RecvPClientHandleCo
   ClientHandleParent* actor = static_cast<ClientHandleParent*>(aActor);
   actor->Init(aClientInfo);
   return IPC_OK();
 }
 
 PClientManagerOpParent*
 ClientManagerParent::AllocPClientManagerOpParent(const ClientOpConstructorArgs& aArgs)
 {
-  return new ClientManagerOpParent();
+  return new ClientManagerOpParent(mService);
 }
 
 bool
 ClientManagerParent::DeallocPClientManagerOpParent(PClientManagerOpParent* aActor)
 {
   delete aActor;
   return true;
 }
@@ -96,16 +97,17 @@ ClientManagerParent::AllocPClientSourceP
 bool
 ClientManagerParent::DeallocPClientSourceParent(PClientSourceParent* aActor)
 {
   delete aActor;
   return true;
 }
 
 ClientManagerParent::ClientManagerParent()
+  : mService(ClientManagerService::GetOrCreateInstance())
 {
 }
 
 ClientManagerParent::~ClientManagerParent()
 {
 }
 
 } // namespace dom
--- a/dom/clients/manager/ClientManagerParent.h
+++ b/dom/clients/manager/ClientManagerParent.h
@@ -6,18 +6,22 @@
 #ifndef _mozilla_dom_ClientManagerParent_h
 #define _mozilla_dom_ClientManagerParent_h
 
 #include "mozilla/dom/PClientManagerParent.h"
 
 namespace mozilla {
 namespace dom {
 
+class ClientManagerService;
+
 class ClientManagerParent final : public PClientManagerParent
 {
+  RefPtr<ClientManagerService> mService;
+
   // PClientManagerParent interface
   mozilla::ipc::IPCResult
   RecvTeardown() override;
 
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
   PClientHandleParent*
new file mode 100644
--- /dev/null
+++ b/dom/clients/manager/ClientManagerService.cpp
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "ClientManagerService.h"
+
+#include "mozilla/ipc/BackgroundParent.h"
+
+namespace mozilla {
+namespace dom {
+
+using mozilla::ipc::AssertIsOnBackgroundThread;
+using mozilla::ipc::ContentPrincipalInfo;
+
+namespace {
+
+ClientManagerService* sClientManagerServiceInstance = nullptr;
+
+bool
+MatchPrincipalInfo(const PrincipalInfo& aLeft, const PrincipalInfo& aRight)
+{
+  if (aLeft.type() != aRight.type()) {
+    return false;
+  }
+
+  switch (aLeft.type()) {
+    case PrincipalInfo::TContentPrincipalInfo:
+    {
+      const ContentPrincipalInfo& leftContent = aLeft.get_ContentPrincipalInfo();
+      const ContentPrincipalInfo& rightContent = aRight.get_ContentPrincipalInfo();
+      return leftContent.attrs() == rightContent.attrs() &&
+             leftContent.originNoSuffix() == rightContent.originNoSuffix();
+    }
+    case PrincipalInfo::TSystemPrincipalInfo:
+    {
+      // system principal always matches
+      return true;
+    }
+    case PrincipalInfo::TNullPrincipalInfo:
+    {
+      // null principal never matches
+      return false;
+    }
+    default:
+    {
+      break;
+    }
+  }
+
+  // Clients (windows/workers) should never have an expanded principal type.
+  MOZ_CRASH("unexpected principal type!");
+}
+
+} // anonymous namespace
+
+ClientManagerService::ClientManagerService()
+{
+  AssertIsOnBackgroundThread();
+}
+
+ClientManagerService::~ClientManagerService()
+{
+  AssertIsOnBackgroundThread();
+  MOZ_DIAGNOSTIC_ASSERT(mSourceTable.Count() == 0);
+
+  MOZ_DIAGNOSTIC_ASSERT(sClientManagerServiceInstance == this);
+  sClientManagerServiceInstance = nullptr;
+}
+
+// static
+already_AddRefed<ClientManagerService>
+ClientManagerService::GetOrCreateInstance()
+{
+  AssertIsOnBackgroundThread();
+
+  if (!sClientManagerServiceInstance) {
+    sClientManagerServiceInstance = new ClientManagerService();
+  }
+
+  RefPtr<ClientManagerService> ref(sClientManagerServiceInstance);
+  return ref.forget();
+}
+
+void
+ClientManagerService::AddSource(ClientSourceParent* aSource)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aSource);
+  auto entry = mSourceTable.LookupForAdd(aSource->Info().Id());
+  MOZ_DIAGNOSTIC_ASSERT(!entry);
+  entry.OrInsert([&] { return aSource; });
+}
+
+void
+ClientManagerService::RemoveSource(ClientSourceParent* aSource)
+{
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aSource);
+  auto entry = mSourceTable.Lookup(aSource->Info().Id());
+  MOZ_DIAGNOSTIC_ASSERT(entry);
+  entry.Remove();
+}
+
+ClientSourceParent*
+ClientManagerService::FindSource(const nsID& aID, const PrincipalInfo& aPrincipalInfo)
+{
+  AssertIsOnBackgroundThread();
+
+  auto entry = mSourceTable.Lookup(aID);
+  if (!entry) {
+    return nullptr;
+  }
+
+  ClientSourceParent* source = entry.Data();
+  if (!MatchPrincipalInfo(source->Info().PrincipalInfo(), aPrincipalInfo)) {
+    return nullptr;
+  }
+
+  return source;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/clients/manager/ClientManagerService.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 _mozilla_dom_ClientManagerService_h
+#define _mozilla_dom_ClientManagerService_h
+
+#include "nsDataHashtable.h"
+
+namespace mozilla {
+
+namespace dom {
+
+class ClientSourceParent;
+
+// Define a singleton service to manage client activity throughout the
+// browser.  This service runs on the PBackground thread.  To interact
+// it with it please use the ClientManager and ClientHandle classes.
+class ClientManagerService final
+{
+  // Store the ClientSourceParent objects in a hash table.  We want to
+  // optimize for insertion, removal, and lookup by UUID.
+  nsDataHashtable<nsIDHashKey, ClientSourceParent*> mSourceTable;
+
+  ClientManagerService();
+  ~ClientManagerService();
+
+public:
+  static already_AddRefed<ClientManagerService>
+  GetOrCreateInstance();
+
+  void
+  AddSource(ClientSourceParent* aSource);
+
+  void
+  RemoveSource(ClientSourceParent* aSource);
+
+  ClientSourceParent*
+  FindSource(const nsID& aID,
+             const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
+
+  NS_INLINE_DECL_REFCOUNTING(mozilla::dom::ClientManagerService)
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // _mozilla_dom_ClientManagerService_h
new file mode 100644
--- /dev/null
+++ b/dom/clients/manager/ClientSource.cpp
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "ClientSource.h"
+
+#include "ClientManager.h"
+#include "ClientManagerChild.h"
+#include "ClientSourceChild.h"
+#include "mozilla/dom/ClientIPCTypes.h"
+
+namespace mozilla {
+namespace dom {
+
+using mozilla::ipc::PrincipalInfo;
+
+void
+ClientSource::Shutdown()
+{
+  NS_ASSERT_OWNINGTHREAD(ClientSource);
+  if (IsShutdown()) {
+    return;
+  }
+
+  ShutdownThing();
+
+  mManager = nullptr;
+}
+
+ClientSource::ClientSource(ClientManager* aManager,
+                           const ClientSourceConstructorArgs& aArgs)
+  : mManager(aManager)
+  , mClientInfo(aArgs.id(), aArgs.type(), aArgs.principalInfo(), aArgs.creationTime())
+{
+  MOZ_ASSERT(mManager);
+}
+
+void
+ClientSource::Activate(PClientManagerChild* aActor)
+{
+  NS_ASSERT_OWNINGTHREAD(ClientSource);
+  MOZ_ASSERT(!GetActor());
+
+  if (IsShutdown()) {
+    return;
+  }
+
+  ClientSourceConstructorArgs args(mClientInfo.Id(), mClientInfo.Type(),
+                                   mClientInfo.PrincipalInfo(),
+                                   mClientInfo.CreationTime());
+  PClientSourceChild* actor = aActor->SendPClientSourceConstructor(args);
+  if (!actor) {
+    Shutdown();
+    return;
+  }
+
+  ActivateThing(static_cast<ClientSourceChild*>(actor));
+}
+
+ClientSource::~ClientSource()
+{
+  Shutdown();
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/clients/manager/ClientSource.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 _mozilla_dom_ClientSource_h
+#define _mozilla_dom_ClientSource_h
+
+#include "mozilla/dom/ClientInfo.h"
+#include "mozilla/dom/ClientThing.h"
+
+namespace mozilla {
+namespace dom {
+
+class ClientManager;
+class ClientSourceChild;
+class ClientSourceConstructorArgs;
+class PClientManagerChild;
+
+namespace workers {
+class WorkerPrivate;
+} // workers namespace
+
+// ClientSource is an RAII style class that is designed to be held via
+// a UniquePtr<>.  When created ClientSource will register the existence
+// of a client in the cross-process ClientManagerService.  When the
+// ClientSource is destroyed then client entry will be removed.  Code
+// that represents globals or browsing environments, such as nsGlobalWindow
+// or WorkerPrivate, should use ClientManager to create a ClientSource.
+class ClientSource final : public ClientThing<ClientSourceChild>
+{
+  friend class ClientManager;
+
+  NS_DECL_OWNINGTHREAD
+
+  RefPtr<ClientManager> mManager;
+
+  ClientInfo mClientInfo;
+
+  void
+  Shutdown();
+
+  // Private methods called by ClientManager
+  ClientSource(ClientManager* aManager,
+               const ClientSourceConstructorArgs& aArgs);
+
+  void
+  Activate(PClientManagerChild* aActor);
+
+public:
+  ~ClientSource();
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // _mozilla_dom_ClientSource_h
--- a/dom/clients/manager/ClientSourceChild.cpp
+++ b/dom/clients/manager/ClientSourceChild.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "ClientSourceChild.h"
 
 #include "ClientSourceOpChild.h"
+#include "ClientThing.h"
 #include "mozilla/dom/ClientIPCTypes.h"
 #include "mozilla/Unused.h"
 
 namespace mozilla {
 namespace dom {
 
 using mozilla::ipc::IPCResult;
 
--- a/dom/clients/manager/ClientSourceParent.cpp
+++ b/dom/clients/manager/ClientSourceParent.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "ClientSourceParent.h"
 
 #include "ClientHandleParent.h"
+#include "ClientManagerService.h"
 #include "ClientSourceOpParent.h"
 #include "mozilla/dom/ClientIPCTypes.h"
 #include "mozilla/Unused.h"
 
 namespace mozilla {
 namespace dom {
 
 using mozilla::ipc::IPCResult;
@@ -22,16 +23,25 @@ ClientSourceParent::RecvTeardown()
 {
   Unused << Send__delete__(this);
   return IPC_OK();
 }
 
 void
 ClientSourceParent::ActorDestroy(ActorDestroyReason aReason)
 {
+  mService->RemoveSource(this);
+
+  nsTArray<ClientHandleParent*> handleList(mHandleList);
+  for (ClientHandleParent* handle : handleList) {
+    // This should trigger DetachHandle() to be called removing
+    // the entry from the mHandleList.
+    Unused << ClientHandleParent::Send__delete__(handle);
+  }
+  MOZ_DIAGNOSTIC_ASSERT(mHandleList.IsEmpty());
 }
 
 PClientSourceOpParent*
 ClientSourceParent::AllocPClientSourceOpParent(const ClientOpConstructorArgs& aArgs)
 {
   MOZ_ASSERT_UNREACHABLE("ClientSourceOpParent should be explicitly constructed.");
   return nullptr;
 }
@@ -39,17 +49,43 @@ ClientSourceParent::AllocPClientSourceOp
 bool
 ClientSourceParent::DeallocPClientSourceOpParent(PClientSourceOpParent* aActor)
 {
   delete aActor;
   return true;
 }
 
 ClientSourceParent::ClientSourceParent(const ClientSourceConstructorArgs& aArgs)
+  : mClientInfo(aArgs.id(), aArgs.type(), aArgs.principalInfo(), aArgs.creationTime())
+  , mService(ClientManagerService::GetOrCreateInstance())
 {
+  mService->AddSource(this);
 }
 
 ClientSourceParent::~ClientSourceParent()
 {
+  MOZ_DIAGNOSTIC_ASSERT(mHandleList.IsEmpty());
+}
+
+const ClientInfo&
+ClientSourceParent::Info() const
+{
+  return mClientInfo;
+}
+
+void
+ClientSourceParent::AttachHandle(ClientHandleParent* aClientHandle)
+{
+  MOZ_DIAGNOSTIC_ASSERT(aClientHandle);
+  MOZ_ASSERT(!mHandleList.Contains(aClientHandle));
+  mHandleList.AppendElement(aClientHandle);
+}
+
+void
+ClientSourceParent::DetachHandle(ClientHandleParent* aClientHandle)
+{
+  MOZ_DIAGNOSTIC_ASSERT(aClientHandle);
+  MOZ_ASSERT(mHandleList.Contains(aClientHandle));
+  mHandleList.RemoveElement(aClientHandle);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientSourceParent.h
+++ b/dom/clients/manager/ClientSourceParent.h
@@ -1,37 +1,54 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 _mozilla_dom_ClientSourceParent_h
 #define _mozilla_dom_ClientSourceParent_h
 
+#include "ClientInfo.h"
 #include "mozilla/dom/PClientSourceParent.h"
 
 namespace mozilla {
 namespace dom {
 
+class ClientHandleParent;
+class ClientManagerService;
+
 class ClientSourceParent final : public PClientSourceParent
 {
+  ClientInfo mClientInfo;
+  RefPtr<ClientManagerService> mService;
+  nsTArray<ClientHandleParent*> mHandleList;
+
   // PClientSourceParent
   IPCResult
   RecvTeardown() override;
 
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
   PClientSourceOpParent*
   AllocPClientSourceOpParent(const ClientOpConstructorArgs& aArgs) override;
 
   bool
   DeallocPClientSourceOpParent(PClientSourceOpParent* aActor) override;
 
 public:
   explicit ClientSourceParent(const ClientSourceConstructorArgs& aArgs);
   ~ClientSourceParent();
+
+  const ClientInfo&
+  Info() const;
+
+  void
+  AttachHandle(ClientHandleParent* aClientSource);
+
+  void
+  DetachHandle(ClientHandleParent* aClientSource);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientSourceParent_h
--- a/dom/clients/manager/ClientThing.h
+++ b/dom/clients/manager/ClientThing.h
@@ -94,15 +94,20 @@ public:
   // Clear the weak references between the thing and its IPC actor.
   void
   RevokeActor(ActorType* aActor)
   {
     MOZ_DIAGNOSTIC_ASSERT(mActor);
     MOZ_DIAGNOSTIC_ASSERT(mActor == aActor);
     mActor->RevokeOwner(this);
     mActor = nullptr;
+
+    // Also consider the ClientThing shutdown.  We simply set the flag
+    // instead of calling ShutdownThing() to avoid calling MaybeStartTeardown()
+    // on the destroyed actor.
+    mShutdown = true;
   }
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientThing_h
--- a/dom/clients/manager/moz.build
+++ b/dom/clients/manager/moz.build
@@ -1,40 +1,47 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 EXPORTS.mozilla.dom += [
+  'ClientHandle.h',
   'ClientInfo.h',
   'ClientIPCUtils.h',
+  'ClientManager.h',
   'ClientManagerActors.h',
   'ClientOpenWindowOpActors.h',
   'ClientOpPromise.h',
+  'ClientSource.h',
   'ClientState.h',
   'ClientThing.h',
 ]
 
 UNIFIED_SOURCES += [
+  'ClientHandle.cpp',
   'ClientHandleChild.cpp',
   'ClientHandleOpChild.cpp',
   'ClientHandleOpParent.cpp',
   'ClientHandleParent.cpp',
   'ClientInfo.cpp',
+  'ClientManager.cpp',
   'ClientManagerActors.cpp',
   'ClientManagerChild.cpp',
   'ClientManagerOpChild.cpp',
   'ClientManagerOpParent.cpp',
   'ClientManagerParent.cpp',
+  'ClientManagerService.cpp',
   'ClientNavigateOpChild.cpp',
   'ClientNavigateOpParent.cpp',
   'ClientOpenWindowOpActors.cpp',
   'ClientOpenWindowOpChild.cpp',
   'ClientOpenWindowOpParent.cpp',
+  'ClientSource.cpp',
   'ClientSourceChild.cpp',
   'ClientSourceOpChild.cpp',
   'ClientSourceOpParent.cpp',
   'ClientSourceParent.cpp',
   'ClientState.cpp',
 ]
 
 IPDL_SOURCES += [
@@ -47,16 +54,17 @@ IPDL_SOURCES += [
   'PClientOpenWindowOp.ipdl',
   'PClientSource.ipdl',
   'PClientSourceOp.ipdl',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
+  '/dom/workers',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 MOCHITEST_MANIFESTS += [
 ]
 
 BROWSER_CHROME_MANIFESTS += [
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -17,16 +17,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
 #include "mozilla/Unused.h"
 #include "mozilla/TelemetryIPC.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
+#include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientOpenWindowOpActors.h"
 #include "mozilla/dom/ContentBridgeChild.h"
 #include "mozilla/dom/ContentBridgeParent.h"
 #include "mozilla/dom/VideoDecoderManagerChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
@@ -1149,16 +1150,18 @@ ContentChild::InitXPCOM(const XPCOMInitD
   BackgroundChild::Startup();
 
   PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
   if (NS_WARN_IF(!actorChild)) {
     MOZ_ASSERT_UNREACHABLE("PBackground init can't fail at this point");
     return;
   }
 
+  ClientManager::Startup();
+
   nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   if (!svc) {
     NS_WARNING("Couldn't acquire console service");
     return;
   }
 
   mConsoleListener = new ConsoleListener(this);
   if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -29,16 +29,17 @@
 #include "mozilla/a11y/Compatibility.h"
 #endif
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/DataStorage.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
 #include "mozilla/docshell/OfflineCacheUpdateParent.h"
+#include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientOpenWindowOpActors.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileCreatorHelper.h"
 #include "mozilla/dom/FileSystemSecurity.h"
 #include "mozilla/dom/IPCBlobUtils.h"
 #include "mozilla/dom/ExternalHelperAppParent.h"
@@ -623,16 +624,17 @@ ContentParent::StartUp()
   }
 
   // Note: This reporter measures all ContentParents.
   RegisterStrongMemoryReporter(new ContentParentsMemoryReporter());
 
   mozilla::dom::time::InitializeDateCacheCleaner();
 
   BackgroundChild::Startup();
+  ClientManager::Startup();
 
   sDisableUnsafeCPOWWarnings = PR_GetEnv("DISABLE_UNSAFE_CPOW_WARNINGS");
 
 #if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
   sSandboxBrokerPolicyFactory = MakeUnique<SandboxBrokerPolicyFactory>();
 #endif
 }
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/oom-wasm-streaming.js
@@ -0,0 +1,12 @@
+try {
+    WebAssembly.compileStreaming();
+} catch (err) {
+    assertEq(String(err).indexOf("not supported with --no-threads") !== -1, true);
+    quit();
+}
+if (!this.oomAfterAllocations)
+    quit();
+oomAfterAllocations(1, 2);
+var x = wasmTextToBinary('(module (func (export "run") (result i32) i32.const 42))');
+WebAssembly.compileStreaming(x);
+drainJobQueue();
--- a/js/src/vm/AsyncFunction.cpp
+++ b/js/src/vm/AsyncFunction.cpp
@@ -130,18 +130,17 @@ js::WrapAsyncFunctionWithProto(JSContext
     uint16_t length;
     if (!JSFunction::getLength(cx, unwrapped, &length))
         return nullptr;
 
     // Steps 3 (partially).
     RootedFunction wrapped(cx, NewFunctionWithProto(cx, WrappedAsyncFunction, length,
                                                     JSFunction::NATIVE_FUN, nullptr,
                                                     funName, proto,
-                                                    AllocKind::FUNCTION_EXTENDED,
-                                                    TenuredObject));
+                                                    AllocKind::FUNCTION_EXTENDED));
     if (!wrapped)
         return nullptr;
 
     if (unwrapped->hasCompileTimeName())
         wrapped->setCompileTimeName(unwrapped->compileTimeName());
 
     // Link them to each other to make GetWrappedAsyncFunction and
     // GetUnwrappedAsyncFunction work.
--- a/js/src/vm/AsyncIteration.cpp
+++ b/js/src/vm/AsyncIteration.cpp
@@ -75,18 +75,17 @@ js::WrapAsyncGeneratorWithProto(JSContex
     RootedAtom funName(cx, unwrapped->explicitName());
     uint16_t length;
     if (!JSFunction::getLength(cx, unwrapped, &length))
         return nullptr;
 
     RootedFunction wrapped(cx, NewFunctionWithProto(cx, WrappedAsyncGenerator, length,
                                                     JSFunction::NATIVE_FUN, nullptr,
                                                     funName, proto,
-                                                    AllocKind::FUNCTION_EXTENDED,
-                                                    TenuredObject));
+                                                    AllocKind::FUNCTION_EXTENDED));
     if (!wrapped)
         return nullptr;
 
     if (unwrapped->hasCompileTimeName())
         wrapped->setCompileTimeName(unwrapped->compileTimeName());
 
     // Link them to each other to make GetWrappedAsyncGenerator and
     // GetUnwrappedAsyncGenerator work.
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -1847,26 +1847,34 @@ WebAssembly_toSource(JSContext* cx, unsi
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setString(cx->names().WebAssembly);
     return true;
 }
 #endif
 
 static bool
+RejectWithPendingException(JSContext* cx, Handle<PromiseObject*> promise)
+{
+    if (!cx->isExceptionPending())
+        return false;
+
+    RootedValue rejectionValue(cx);
+    if (!GetAndClearException(cx, &rejectionValue))
+        return false;
+
+    return PromiseObject::reject(cx, promise, rejectionValue);
+}
+
+static bool
 Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, Handle<PromiseObject*> promise)
 {
     if (!error) {
         ReportOutOfMemory(cx);
-
-        RootedValue rejectionValue(cx);
-        if (!cx->getPendingException(&rejectionValue))
-            return false;
-
-        return PromiseObject::reject(cx, promise, rejectionValue);
+        return RejectWithPendingException(cx, promise);
     }
 
     RootedObject stack(cx, promise->allocationSite());
     RootedString filename(cx, JS_NewStringCopyZ(cx, args.scriptedCaller.filename.get()));
     if (!filename)
         return false;
 
     unsigned line = args.scriptedCaller.line;
@@ -1888,29 +1896,16 @@ Reject(JSContext* cx, const CompileArgs&
     if (!errorObj)
         return false;
 
     RootedValue rejectionValue(cx, ObjectValue(*errorObj));
     return PromiseObject::reject(cx, promise, rejectionValue);
 }
 
 static bool
-RejectWithPendingException(JSContext* cx, Handle<PromiseObject*> promise)
-{
-    if (!cx->isExceptionPending())
-        return false;
-
-    RootedValue rejectionValue(cx);
-    if (!GetAndClearException(cx, &rejectionValue))
-        return false;
-
-    return PromiseObject::reject(cx, promise, rejectionValue);
-}
-
-static bool
 Resolve(JSContext* cx, Module& module, const CompileArgs& compileArgs,
         Handle<PromiseObject*> promise, bool instantiate, HandleObject importObj)
 {
     RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject());
     RootedObject moduleObj(cx, WasmModuleObject::create(cx, module, proto));
     if (!moduleObj)
         return RejectWithPendingException(cx, promise);
 
@@ -2517,17 +2512,17 @@ ResolveResponse(JSContext* cx, CallArgs 
 
     RootedFunction onResolved(cx, NewNativeFunction(cx, ResolveResponse_OnFulfilled, 1, nullptr,
                                                     gc::AllocKind::FUNCTION_EXTENDED));
     if (!onResolved)
         return false;
 
     RootedFunction onRejected(cx, NewNativeFunction(cx, ResolveResponse_OnRejected, 1, nullptr,
                                                     gc::AllocKind::FUNCTION_EXTENDED));
-    if (!onResolved)
+    if (!onRejected)
         return false;
 
     onResolved->setExtendedSlot(0, ObjectValue(*closure));
     onRejected->setExtendedSlot(0, ObjectValue(*closure));
 
     RootedObject resolve(cx, PromiseObject::unforgeableResolve(cx, callArgs.get(0)));
     if (!resolve)
         return false;