Bug 1539147 - Part 2: Refactor WindowGlobalParent and WindowGlobalChild; r=nika
☠☠ backed out by 1acfb43661fd ☠ ☠
authorJohn Dai <jdai@mozilla.com>
Fri, 03 May 2019 15:31:04 +0000
changeset 472507 366f29cc8ce7caedd57c830b8febd02aac3edd1d
parent 472506 5fa4ae41da870759e7cd3531f81604e8f87bc589
child 472508 376d2f3bd8d97d0dd6a10566503fcc83f75dcdea
push id35958
push usermalexandru@mozilla.com
push dateFri, 03 May 2019 21:56:39 +0000
treeherdermozilla-central@eb5b01e0b309 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika
bugs1539147
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1539147 - Part 2: Refactor WindowGlobalParent and WindowGlobalChild; r=nika Differential Revision: https://phabricator.services.mozilla.com/D29427
dom/ipc/JSWindowActor.h
dom/ipc/JSWindowActorService.cpp
dom/ipc/JSWindowActorService.h
dom/ipc/WindowGlobalActor.cpp
dom/ipc/WindowGlobalActor.h
dom/ipc/WindowGlobalChild.cpp
dom/ipc/WindowGlobalChild.h
dom/ipc/WindowGlobalParent.cpp
dom/ipc/WindowGlobalParent.h
dom/ipc/moz.build
--- a/dom/ipc/JSWindowActor.h
+++ b/dom/ipc/JSWindowActor.h
@@ -9,16 +9,18 @@
 
 #include "js/TypeDecls.h"
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "nsRefPtrHashtable.h"
 
+class nsIGlobalObject;
+
 namespace mozilla {
 namespace dom {
 
 enum class JSWindowActorMessageKind {
   Message,
   Query,
   QueryResolve,
   QueryReject,
@@ -31,16 +33,18 @@ class QueryPromiseHandler;
 // Common base class for JSWindowActor{Parent,Child}.
 class JSWindowActor : public nsISupports, public nsWrapperCache {
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(JSWindowActor)
 
   JSWindowActor();
 
+  enum class Type { Parent, Child };
+
   const nsString& Name() const { return mName; }
 
   void SendAsyncMessage(JSContext* aCx, const nsAString& aMessageName,
                         JS::Handle<JS::Value> aObj,
                         JS::Handle<JS::Value> aTransfers, ErrorResult& aRv);
 
   already_AddRefed<Promise> SendQuery(JSContext* aCx,
                                       const nsAString& aMessageName,
--- a/dom/ipc/JSWindowActorService.cpp
+++ b/dom/ipc/JSWindowActorService.cpp
@@ -3,108 +3,43 @@
 /* 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 "mozilla/dom/JSWindowActorService.h"
 #include "mozilla/dom/ChromeUtilsBinding.h"
 #include "mozilla/dom/EventListenerBinding.h"
-#include "mozilla/EventListenerManager.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/EventTarget.h"
 #include "mozilla/dom/JSWindowActorBinding.h"
 #include "mozilla/dom/JSWindowActorChild.h"
 #include "mozilla/dom/MessageManagerBinding.h"
 #include "mozilla/dom/PContent.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/WindowGlobalChild.h"
 #include "mozilla/StaticPtr.h"
-#include "mozJSComponentLoader.h"
-#include "mozilla/extensions/WebExtensionContentScript.h"
 #include "mozilla/Logging.h"
 
-#include "nsIObserver.h"
-#include "nsIDOMEventListener.h"
-
 namespace mozilla {
 namespace dom {
 namespace {
 StaticRefPtr<JSWindowActorService> gJSWindowActorService;
 }
 
-/**
- * Object corresponding to a single actor protocol. This object acts as an
- * Event listener for the actor which is called for events which would
- * trigger actor creation.
- *
- * This object also can act as a carrier for methods and other state related to
- * a single protocol managed by the JSWindowActorService.
- */
-class JSWindowActorProtocol final : public nsIObserver,
-                                    public nsIDOMEventListener {
- public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIOBSERVER
-  NS_DECL_NSIDOMEVENTLISTENER
-
-  static already_AddRefed<JSWindowActorProtocol> FromIPC(
-      const JSWindowActorInfo& aInfo);
-  JSWindowActorInfo ToIPC();
-
-  static already_AddRefed<JSWindowActorProtocol> FromWebIDLOptions(
-      const nsAString& aName, const WindowActorOptions& aOptions,
-      ErrorResult& aRv);
-
-  struct Sided {
-    nsCString mModuleURI;
-  };
-
-  struct ParentSide : public Sided {};
+NS_IMPL_CYCLE_COLLECTING_ADDREF(JSWindowActorProtocol)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(JSWindowActorProtocol)
 
-  struct EventDecl {
-    nsString mName;
-    EventListenerFlags mFlags;
-    Optional<bool> mPassive;
-  };
-
-  struct ChildSide : public Sided {
-    nsTArray<EventDecl> mEvents;
-    nsTArray<nsCString> mObservers;
-  };
-
-  const ParentSide& Parent() const { return mParent; }
-  const ChildSide& Child() const { return mChild; }
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JSWindowActorProtocol)
+  NS_INTERFACE_MAP_ENTRY(nsIObserver)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
+NS_INTERFACE_MAP_END
 
-  void RegisterListenersFor(EventTarget* aRoot);
-  void UnregisterListenersFor(EventTarget* aRoot);
-  void AddObservers();
-  void RemoveObservers();
-  bool Matches(BrowsingContext* aBrowsingContext, nsIURI* aURI,
-               const nsString& aRemoteType);
-
- private:
-  explicit JSWindowActorProtocol(const nsAString& aName) : mName(aName) {}
-  extensions::MatchPatternSet* GetURIMatcher();
-  ~JSWindowActorProtocol() = default;
-
-  nsString mName;
-  bool mAllFrames = false;
-  bool mIncludeChrome = false;
-  nsTArray<nsString> mMatches;
-  nsTArray<nsString> mRemoteTypes;
-
-  ParentSide mParent;
-  ChildSide mChild;
-
-  RefPtr<extensions::MatchPatternSet> mURIMatcher;
-};
-
-NS_IMPL_ISUPPORTS(JSWindowActorProtocol, nsIObserver, nsIDOMEventListener);
+NS_IMPL_CYCLE_COLLECTION(JSWindowActorProtocol, mURIMatcher)
 
 /* static */ already_AddRefed<JSWindowActorProtocol>
 JSWindowActorProtocol::FromIPC(const JSWindowActorInfo& aInfo) {
   MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess());
 
   RefPtr<JSWindowActorProtocol> proto = new JSWindowActorProtocol(aInfo.name());
   // Content processes cannot load chrome browsing contexts, so this flag is
   // irrelevant and not propagated.
@@ -355,17 +290,21 @@ extensions::MatchPatternSet* JSWindowAct
   // Make MatchPattern's mSchemes create properly.
   matchPatternOptions.mRestrictSchemes = false;
   mURIMatcher = extensions::MatchPatternSet::Constructor(
       global, patterns, matchPatternOptions, IgnoreErrors());
   return mURIMatcher;
 }
 
 bool JSWindowActorProtocol::Matches(BrowsingContext* aBrowsingContext,
-                                    nsIURI* aURI, const nsString& aRemoteType) {
+                                    nsIURI* aURI,
+                                    const nsAString& aRemoteType) {
+  MOZ_ASSERT(aBrowsingContext, "DocShell without a BrowsingContext!");
+  MOZ_ASSERT(aURI, "Must have URI!");
+
   if (!mRemoteTypes.IsEmpty() && !mRemoteTypes.Contains(aRemoteType)) {
     return false;
   }
 
   if (!mAllFrames && aBrowsingContext->GetParent()) {
     return false;
   }
 
@@ -484,79 +423,16 @@ void JSWindowActorService::GetJSWindowAc
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(XRE_IsParentProcess());
 
   for (auto iter = mDescriptors.ConstIter(); !iter.Done(); iter.Next()) {
     aInfos.AppendElement(iter.Data()->ToIPC());
   }
 }
 
-void JSWindowActorService::ConstructActor(
-    const nsAString& aName, bool aParentSide, BrowsingContext* aBrowsingContext,
-    nsIURI* aURI, const nsString& aRemoteType, JS::MutableHandleObject aActor,
-    ErrorResult& aRv) {
-  MOZ_ASSERT_IF(aParentSide, XRE_IsParentProcess());
-  MOZ_ASSERT(aBrowsingContext, "DocShell without a BrowsingContext!");
-  MOZ_ASSERT(aURI, "Must have URI!");
-  // Constructing an actor requires a running script, so push an AutoEntryScript
-  // onto the stack.
-  AutoEntryScript aes(xpc::PrivilegedJunkScope(), "JSWindowActor construction");
-  JSContext* cx = aes.cx();
-
-  // Load our descriptor
-  RefPtr<JSWindowActorProtocol> proto = mDescriptors.Get(aName);
-  if (!proto) {
-    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-    return;
-  }
-
-  const JSWindowActorProtocol::Sided* side;
-  if (aParentSide) {
-    side = &proto->Parent();
-  } else {
-    side = &proto->Child();
-  }
-
-  // Check if our current BrowsingContext and URI matches the requirements for
-  // this actor to load.
-  if (!proto->Matches(aBrowsingContext, aURI, aRemoteType)) {
-    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
-    return;
-  }
-
-  // Load the module using mozJSComponentLoader.
-  RefPtr<mozJSComponentLoader> loader = mozJSComponentLoader::Get();
-  MOZ_ASSERT(loader);
-
-  JS::RootedObject global(cx);
-  JS::RootedObject exports(cx);
-  aRv = loader->Import(cx, side->mModuleURI, &global, &exports);
-  if (aRv.Failed()) {
-    return;
-  }
-  MOZ_ASSERT(exports, "null exports!");
-
-  // Load the specific property from our module.
-  JS::RootedValue ctor(cx);
-  nsAutoString ctorName(aName);
-  ctorName.Append(aParentSide ? NS_LITERAL_STRING("Parent")
-                              : NS_LITERAL_STRING("Child"));
-  if (!JS_GetUCProperty(cx, exports, ctorName.get(), ctorName.Length(),
-                        &ctor)) {
-    aRv.NoteJSContextException(cx);
-    return;
-  }
-
-  // Invoke the constructor loaded from the module.
-  if (!JS::Construct(cx, ctor, JS::HandleValueArray::empty(), aActor)) {
-    aRv.NoteJSContextException(cx);
-    return;
-  }
-}
-
 void JSWindowActorService::RegisterWindowRoot(EventTarget* aRoot) {
   MOZ_ASSERT(!mRoots.Contains(aRoot));
   mRoots.AppendElement(aRoot);
 
   // Register event listeners on the newly added Window Root.
   for (auto iter = mDescriptors.Iter(); !iter.Done(); iter.Next()) {
     iter.Data()->RegisterListenersFor(aRoot);
   }
@@ -565,10 +441,15 @@ void JSWindowActorService::RegisterWindo
 /* static */
 void JSWindowActorService::UnregisterWindowRoot(EventTarget* aRoot) {
   if (gJSWindowActorService) {
     // NOTE: No need to unregister listeners here, as the root is going away.
     gJSWindowActorService->mRoots.RemoveElement(aRoot);
   }
 }
 
+already_AddRefed<JSWindowActorProtocol> JSWindowActorService::GetProtocol(
+    const nsAString& aName) {
+  return mDescriptors.Get(aName);
+}
+
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/ipc/JSWindowActorService.h
+++ b/dom/ipc/JSWindowActorService.h
@@ -8,24 +8,97 @@
 #define mozilla_dom_JSWindowActorService_h
 
 #include "mozilla/dom/BrowsingContext.h"
 #include "mozilla/ErrorResult.h"
 #include "nsIURI.h"
 #include "nsRefPtrHashtable.h"
 #include "nsString.h"
 #include "nsTArray.h"
+#include "mozilla/dom/JSWindowActor.h"
+
+#include "nsIObserver.h"
+#include "nsIDOMEventListener.h"
+#include "mozilla/EventListenerManager.h"
+#include "mozilla/extensions/WebExtensionContentScript.h"
 
 namespace mozilla {
 namespace dom {
 struct WindowActorOptions;
 class JSWindowActorInfo;
-class JSWindowActorProtocol;
 class EventTarget;
 
+/**
+ * Object corresponding to a single actor protocol. This object acts as an
+ * Event listener for the actor which is called for events which would
+ * trigger actor creation.
+ *
+ * This object also can act as a carrier for methods and other state related to
+ * a single protocol managed by the JSWindowActorService.
+ */
+class JSWindowActorProtocol final : public nsIObserver,
+                                    public nsIDOMEventListener {
+ public:
+  NS_DECL_NSIOBSERVER
+  NS_DECL_NSIDOMEVENTLISTENER
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(JSWindowActorProtocol, nsIObserver)
+
+  static already_AddRefed<JSWindowActorProtocol> FromIPC(
+      const JSWindowActorInfo& aInfo);
+  JSWindowActorInfo ToIPC();
+
+  static already_AddRefed<JSWindowActorProtocol> FromWebIDLOptions(
+      const nsAString& aName, const WindowActorOptions& aOptions,
+      ErrorResult& aRv);
+
+  struct Sided {
+    nsCString mModuleURI;
+  };
+
+  struct ParentSide : public Sided {};
+
+  struct EventDecl {
+    nsString mName;
+    EventListenerFlags mFlags;
+    Optional<bool> mPassive;
+  };
+
+  struct ChildSide : public Sided {
+    nsTArray<EventDecl> mEvents;
+    nsTArray<nsCString> mObservers;
+  };
+
+  const ParentSide& Parent() const { return mParent; }
+  const ChildSide& Child() const { return mChild; }
+
+  void RegisterListenersFor(EventTarget* aRoot);
+  void UnregisterListenersFor(EventTarget* aRoot);
+  void AddObservers();
+  void RemoveObservers();
+  bool Matches(BrowsingContext* aBrowsingContext, nsIURI* aURI,
+               const nsAString& aRemoteType);
+
+ private:
+  explicit JSWindowActorProtocol(const nsAString& aName) : mName(aName) {}
+  extensions::MatchPatternSet* GetURIMatcher();
+  ~JSWindowActorProtocol() = default;
+
+  nsString mName;
+  bool mAllFrames = false;
+  bool mIncludeChrome = false;
+  nsTArray<nsString> mMatches;
+  nsTArray<nsString> mRemoteTypes;
+
+  ParentSide mParent;
+  ChildSide mChild;
+
+  RefPtr<extensions::MatchPatternSet> mURIMatcher;
+};
+
 class JSWindowActorService final {
  public:
   NS_INLINE_DECL_REFCOUNTING(JSWindowActorService)
 
   static already_AddRefed<JSWindowActorService> GetSingleton();
 
   void RegisterWindowActor(const nsAString& aName,
                            const WindowActorOptions& aOptions,
@@ -35,30 +108,24 @@ class JSWindowActorService final {
 
   // Register child's Window Actor from JSWindowActorInfos for content process.
   void LoadJSWindowActorInfos(nsTArray<JSWindowActorInfo>& aInfos);
 
   // Get the named of Window Actor and the child's WindowActorOptions
   // from mDescriptors to JSWindowActorInfos.
   void GetJSWindowActorInfos(nsTArray<JSWindowActorInfo>& aInfos);
 
-  // Load the module for the named Window Actor and contruct it.
-  // This method will not initialize the actor or set its manager,
-  // which is handled by callers.
-  void ConstructActor(const nsAString& aName, bool aParentSide,
-                      BrowsingContext* aBrowsingContext, nsIURI* aURI,
-                      const nsString& aRemoteType,
-                      JS::MutableHandleObject aActor, ErrorResult& aRv);
-
   // Register or unregister a WindowRoot object from this JSWindowActorService.
   void RegisterWindowRoot(EventTarget* aRoot);
 
   // NOTE: This method is static, as it may be called during shutdown.
   static void UnregisterWindowRoot(EventTarget* aRoot);
 
+  already_AddRefed<JSWindowActorProtocol> GetProtocol(const nsAString& aName);
+
  private:
   JSWindowActorService();
   ~JSWindowActorService();
 
   nsTArray<EventTarget*> mRoots;
   nsRefPtrHashtable<nsStringHashKey, JSWindowActorProtocol> mDescriptors;
 };
 
new file mode 100644
--- /dev/null
+++ b/dom/ipc/WindowGlobalActor.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "mozilla/dom/WindowGlobalActor.h"
+
+#include "mozJSComponentLoader.h"
+#include "mozilla/Logging.h"
+#include "mozilla/dom/JSWindowActorService.h"
+
+namespace mozilla {
+namespace dom {
+
+void WindowGlobalActor::ConstructActor(const nsAString& aName,
+                                       JS::MutableHandleObject aActor,
+                                       ErrorResult& aRv) {
+  JSWindowActor::Type actorType = GetSide();
+  MOZ_ASSERT_IF(actorType == JSWindowActor::Type::Parent,
+                XRE_IsParentProcess());
+
+  // Constructing an actor requires a running script, so push an AutoEntryScript
+  // onto the stack.
+  AutoEntryScript aes(xpc::PrivilegedJunkScope(), "WindowGlobalActor construction");
+  JSContext* cx = aes.cx();
+
+  RefPtr<JSWindowActorService> actorSvc = JSWindowActorService::GetSingleton();
+  if (!actorSvc) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return;
+  }
+
+  RefPtr<JSWindowActorProtocol> proto = actorSvc->GetProtocol(aName);
+  if (!proto) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return;
+  }
+
+  if (!proto->Matches(BrowsingContext(), GetDocumentURI(), GetRemoteType())) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return;
+  }
+
+  // Load the module using mozJSComponentLoader.
+  RefPtr<mozJSComponentLoader> loader = mozJSComponentLoader::Get();
+  MOZ_ASSERT(loader);
+
+  JS::RootedObject global(cx);
+  JS::RootedObject exports(cx);
+
+  const JSWindowActorProtocol::Sided* side;
+  if (actorType == JSWindowActor::Type::Parent) {
+    side = &proto->Parent();
+  } else {
+    side = &proto->Child();
+  }
+
+  aRv = loader->Import(cx, side->mModuleURI, &global, &exports);
+  if (aRv.Failed()) {
+    return;
+  }
+
+  MOZ_ASSERT(exports, "null exports!");
+
+  // Load the specific property from our module.
+  JS::RootedValue ctor(cx);
+  nsAutoString ctorName(aName);
+  ctorName.Append(actorType == JSWindowActor::Type::Parent
+                      ? NS_LITERAL_STRING("Parent")
+                      : NS_LITERAL_STRING("Child"));
+  if (!JS_GetUCProperty(cx, exports, ctorName.get(), ctorName.Length(),
+                        &ctor)) {
+    aRv.NoteJSContextException(cx);
+    return;
+  }
+
+  // Invoke the constructor loaded from the module.
+  if (!JS::Construct(cx, ctor, JS::HandleValueArray::empty(), aActor)) {
+    aRv.NoteJSContextException(cx);
+    return;
+  }
+}
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowGlobalActor)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WindowGlobalActor)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(WindowGlobalActor)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(WindowGlobalActor)
+
+}  // namespace dom
+}  // namespace mozilla
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/ipc/WindowGlobalActor.h
@@ -0,0 +1,44 @@
+/* -*- 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_WindowGlobalActor_h
+#define mozilla_dom_WindowGlobalActor_h
+
+#include "nsWrapperCache.h"
+#include "nsISupports.h"
+#include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/ErrorResult.h"
+#include "nsIURI.h"
+#include "nsString.h"
+#include "mozilla/dom/JSWindowActor.h"
+
+namespace mozilla {
+namespace dom {
+
+// Common base class for WindowGlobal{Parent, Child}.
+class WindowGlobalActor : public nsISupports, public nsWrapperCache {
+ public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WindowGlobalActor)
+
+ protected:
+  virtual ~WindowGlobalActor() = default;
+
+  // Load the module for the named Window Actor and contruct it.
+  // This method will not initialize the actor or set its manager,
+  // which is handled by callers.
+  void ConstructActor(const nsAString& aName, JS::MutableHandleObject aActor,
+                      ErrorResult& aRv);
+  virtual nsIURI* GetDocumentURI() = 0;
+  virtual const nsAString& GetRemoteType() = 0;
+  virtual JSWindowActor::Type GetSide() = 0;
+  virtual BrowsingContext* BrowsingContext() = 0;
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif  // mozilla_dom_WindowGlobalActor_h
\ No newline at end of file
--- a/dom/ipc/WindowGlobalChild.cpp
+++ b/dom/ipc/WindowGlobalChild.cpp
@@ -238,46 +238,43 @@ void WindowGlobalChild::ReceiveRawMessag
                                           StructuredCloneData&& aData) {
   RefPtr<JSWindowActorChild> actor =
       GetActor(aMeta.actorName(), IgnoreErrors());
   if (actor) {
     actor->ReceiveRawMessage(aMeta, std::move(aData));
   }
 }
 
+nsIURI* WindowGlobalChild::GetDocumentURI() {
+  return mWindowGlobal->GetDocumentURI();
+}
+
+const nsAString& WindowGlobalChild::GetRemoteType() {
+  if (XRE_IsContentProcess()) {
+    return ContentChild::GetSingleton()->GetRemoteType();
+  }
+
+  return VoidString();
+}
+
 already_AddRefed<JSWindowActorChild> WindowGlobalChild::GetActor(
     const nsAString& aName, ErrorResult& aRv) {
   if (mIPCClosed) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   // Check if this actor has already been created, and return it if it has.
   if (mWindowActors.Contains(aName)) {
     return do_AddRef(mWindowActors.GetWeak(aName));
   }
 
-  // Otherwise, we want to create a new instance of this actor. Call into the
-  // JSWindowActorService to trigger construction.
-  RefPtr<JSWindowActorService> actorSvc = JSWindowActorService::GetSingleton();
-  if (!actorSvc) {
-    return nullptr;
-  }
-
-  nsAutoString remoteType;
-  if (XRE_IsContentProcess()) {
-    remoteType = ContentChild::GetSingleton()->GetRemoteType();
-  } else {
-    remoteType = VoidString();
-  }
-
+  // Otherwise, we want to create a new instance of this actor.
   JS::RootedObject obj(RootingCx());
-  actorSvc->ConstructActor(aName, /* aChildSide */ false, mBrowsingContext,
-                           mWindowGlobal->GetDocumentURI(), remoteType, &obj,
-                           aRv);
+  ConstructActor(aName, &obj, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   // Unwrap our actor to a JSWindowActorChild object.
   RefPtr<JSWindowActorChild> actor;
   if (NS_FAILED(UNWRAP_OBJECT(JSWindowActorChild, &obj, actor))) {
     return nullptr;
@@ -311,16 +308,24 @@ JSObject* WindowGlobalChild::WrapObject(
                                         JS::Handle<JSObject*> aGivenProto) {
   return WindowGlobalChild_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 nsISupports* WindowGlobalChild::GetParentObject() {
   return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WindowGlobalChild, mWindowGlobal,
-                                      mBrowsingContext, mWindowActors)
+NS_IMPL_CYCLE_COLLECTION_INHERITED(WindowGlobalChild, WindowGlobalActor,
+                                   mWindowGlobal, mBrowsingContext,
+                                   mWindowActors)
 
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WindowGlobalChild, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WindowGlobalChild, Release)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WindowGlobalChild,
+                                               WindowGlobalActor)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowGlobalChild)
+NS_INTERFACE_MAP_END_INHERITING(WindowGlobalActor)
+
+NS_IMPL_ADDREF_INHERITED(WindowGlobalChild, WindowGlobalActor)
+NS_IMPL_RELEASE_INHERITED(WindowGlobalChild, WindowGlobalActor)
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/ipc/WindowGlobalChild.h
+++ b/dom/ipc/WindowGlobalChild.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_dom_WindowGlobalChild_h
 #define mozilla_dom_WindowGlobalChild_h
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/dom/PWindowGlobalChild.h"
 #include "nsRefPtrHashtable.h"
 #include "nsWrapperCache.h"
+#include "mozilla/dom/WindowGlobalActor.h"
 
 class nsGlobalWindowInner;
 class nsDocShell;
 
 namespace mozilla {
 namespace dom {
 
 class BrowsingContext;
@@ -23,32 +24,34 @@ class WindowGlobalParent;
 class JSWindowActorChild;
 class JSWindowActorMessageMeta;
 class BrowserChild;
 
 /**
  * Actor for a single nsGlobalWindowInner. This actor is used to communicate
  * information to the parent process asynchronously.
  */
-class WindowGlobalChild : public nsWrapperCache, public PWindowGlobalChild {
+class WindowGlobalChild final : public WindowGlobalActor,
+                                public PWindowGlobalChild {
   friend class PWindowGlobalChild;
 
  public:
-  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WindowGlobalChild)
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WindowGlobalChild)
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WindowGlobalChild,
+                                                         WindowGlobalActor)
 
   static already_AddRefed<WindowGlobalChild> GetByInnerWindowId(
       uint64_t aInnerWindowId);
 
   static already_AddRefed<WindowGlobalChild> GetByInnerWindowId(
       const GlobalObject& aGlobal, uint64_t aInnerWindowId) {
     return GetByInnerWindowId(aInnerWindowId);
   }
 
-  dom::BrowsingContext* BrowsingContext() { return mBrowsingContext; }
+  dom::BrowsingContext* BrowsingContext() override { return mBrowsingContext; }
   nsGlobalWindowInner* WindowGlobal() { return mWindowGlobal; }
 
   // Has this actor been shut down
   bool IsClosed() { return mIPCClosed; }
   void Destroy();
 
   // Check if this actor is managed by PInProcess, as-in the document is loaded
   // in the chrome process.
@@ -77,18 +80,24 @@ class WindowGlobalChild : public nsWrapp
 
   // Create and initialize the WindowGlobalChild object.
   static already_AddRefed<WindowGlobalChild> Create(
       nsGlobalWindowInner* aWindow);
 
   nsISupports* GetParentObject();
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
+  nsIURI* GetDocumentURI() override;
 
  protected:
+  const nsAString& GetRemoteType() override;
+  JSWindowActor::Type GetSide() override {
+      return JSWindowActor::Type::Child;
+  }
+
   // IPC messages
   mozilla::ipc::IPCResult RecvRawMessage(const JSWindowActorMessageMeta& aMeta,
                                          const ClonedMessageData& aData);
 
   mozilla::ipc::IPCResult RecvChangeFrameRemoteness(
       dom::BrowsingContext* aBc, const nsString& aRemoteType,
       uint64_t aPendingSwitchId, ChangeFrameRemotenessResolver&& aResolver);
 
--- a/dom/ipc/WindowGlobalParent.cpp
+++ b/dom/ipc/WindowGlobalParent.cpp
@@ -188,45 +188,39 @@ void WindowGlobalParent::ReceiveRawMessa
     const JSWindowActorMessageMeta& aMeta, StructuredCloneData&& aData) {
   RefPtr<JSWindowActorParent> actor =
       GetActor(aMeta.actorName(), IgnoreErrors());
   if (actor) {
     actor->ReceiveRawMessage(aMeta, std::move(aData));
   }
 }
 
+const nsAString& WindowGlobalParent::GetRemoteType() {
+  if (RefPtr<BrowserParent> browserParent = GetRemoteTab()) {
+    return browserParent->Manager()->GetRemoteType();
+  }
+
+  return VoidString();
+}
+
 already_AddRefed<JSWindowActorParent> WindowGlobalParent::GetActor(
     const nsAString& aName, ErrorResult& aRv) {
   if (mIPCClosed) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   // Check if this actor has already been created, and return it if it has.
   if (mWindowActors.Contains(aName)) {
     return do_AddRef(mWindowActors.GetWeak(aName));
   }
 
-  // Otherwise, we want to create a new instance of this actor. Call into the
-  // JSWindowActorService to trigger construction
-  RefPtr<JSWindowActorService> actorSvc = JSWindowActorService::GetSingleton();
-  if (!actorSvc) {
-    return nullptr;
-  }
-
-  nsAutoString remoteType;
-  if (RefPtr<BrowserParent> browserParent = GetRemoteTab()) {
-    remoteType = browserParent->Manager()->GetRemoteType();
-  } else {
-    remoteType = VoidString();
-  }
-
+  // Otherwise, we want to create a new instance of this actor.
   JS::RootedObject obj(RootingCx());
-  actorSvc->ConstructActor(aName, /* aParentSide */ true, mBrowsingContext,
-                           mDocumentURI, remoteType, &obj, aRv);
+  ConstructActor(aName, &obj, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   // Unwrap our actor to a JSWindowActorParent object.
   RefPtr<JSWindowActorParent> actor;
   if (NS_FAILED(UNWRAP_OBJECT(JSWindowActorParent, &obj, actor))) {
     return nullptr;
@@ -322,21 +316,24 @@ JSObject* WindowGlobalParent::WrapObject
                                          JS::Handle<JSObject*> aGivenProto) {
   return WindowGlobalParent_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 nsISupports* WindowGlobalParent::GetParentObject() {
   return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
 }
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowGlobalParent)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
+NS_IMPL_CYCLE_COLLECTION_INHERITED(WindowGlobalParent, WindowGlobalActor,
+                                   mFrameLoader, mBrowsingContext,
+                                   mWindowActors)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WindowGlobalParent, mFrameLoader,
-                                      mBrowsingContext, mWindowActors)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WindowGlobalParent,
+                                               WindowGlobalActor)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(WindowGlobalParent)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(WindowGlobalParent)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowGlobalParent)
+NS_INTERFACE_MAP_END_INHERITING(WindowGlobalActor)
+
+NS_IMPL_ADDREF_INHERITED(WindowGlobalParent, WindowGlobalActor)
+NS_IMPL_RELEASE_INHERITED(WindowGlobalParent, WindowGlobalActor)
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/ipc/WindowGlobalParent.h
+++ b/dom/ipc/WindowGlobalParent.h
@@ -8,40 +8,42 @@
 #define mozilla_dom_WindowGlobalParent_h
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/dom/PWindowGlobalParent.h"
 #include "mozilla/dom/BrowserParent.h"
 #include "nsRefPtrHashtable.h"
 #include "nsWrapperCache.h"
 #include "nsISupports.h"
+#include "mozilla/dom/WindowGlobalActor.h"
+#include "mozilla/dom/CanonicalBrowsingContext.h"
 
 class nsIPrincipal;
 class nsIURI;
 class nsFrameLoader;
 
 namespace mozilla {
 namespace dom {
 
-class CanonicalBrowsingContext;
 class WindowGlobalChild;
 class JSWindowActorParent;
 class JSWindowActorMessageMeta;
 
 /**
  * A handle in the parent process to a specific nsGlobalWindowInner object.
  */
-class WindowGlobalParent final : public nsISupports,
-                                 public nsWrapperCache,
+class WindowGlobalParent final : public WindowGlobalActor,
                                  public PWindowGlobalParent {
   friend class PWindowGlobalParent;
 
  public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WindowGlobalParent)
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WindowGlobalParent,
+                                                         WindowGlobalActor)
+
 
   static already_AddRefed<WindowGlobalParent> GetByInnerWindowId(
       uint64_t aInnerWindowId);
 
   static already_AddRefed<WindowGlobalParent> GetByInnerWindowId(
       const GlobalObject& aGlobal, uint64_t aInnerWindowId) {
     return GetByInnerWindowId(aInnerWindowId);
   }
@@ -69,26 +71,26 @@ class WindowGlobalParent final : public 
                          ipc::StructuredCloneData&& aData);
 
   // The principal of this WindowGlobal. This value will not change over the
   // lifetime of the WindowGlobal object, even to reflect changes in
   // |document.domain|.
   nsIPrincipal* DocumentPrincipal() { return mDocumentPrincipal; }
 
   // The BrowsingContext which this WindowGlobal has been loaded into.
-  CanonicalBrowsingContext* BrowsingContext() { return mBrowsingContext; }
+  CanonicalBrowsingContext* BrowsingContext() override { return mBrowsingContext; }
 
   // Get the root nsFrameLoader object for the tree of BrowsingContext nodes
   // which this WindowGlobal is a part of. This will be the nsFrameLoader
   // holding the BrowserParent for remote tabs, and the root content frameloader
   // for non-remote tabs.
   nsFrameLoader* GetRootFrameLoader() { return mFrameLoader; }
 
   // The current URI which loaded in the document.
-  nsIURI* GetDocumentURI() { return mDocumentURI; }
+  nsIURI* GetDocumentURI() override { return mDocumentURI; }
 
   // Window IDs for inner/outer windows.
   uint64_t OuterWindowId() { return mOuterWindowId; }
   uint64_t InnerWindowId() { return mInnerWindowId; }
 
   bool IsCurrentGlobal();
 
   already_AddRefed<Promise> ChangeFrameRemoteness(dom::BrowsingContext* aBc,
@@ -104,16 +106,21 @@ class WindowGlobalParent final : public 
   // be called after setting the Manager actor.
   void Init(const WindowGlobalInit& aInit);
 
   nsISupports* GetParentObject();
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
  protected:
+  const nsAString& GetRemoteType() override;
+  JSWindowActor::Type GetSide() override {
+      return JSWindowActor::Type::Parent;
+  }
+
   // IPC messages
   mozilla::ipc::IPCResult RecvUpdateDocumentURI(nsIURI* aURI);
   mozilla::ipc::IPCResult RecvBecomeCurrentWindowGlobal();
   mozilla::ipc::IPCResult RecvDestroy();
   mozilla::ipc::IPCResult RecvRawMessage(const JSWindowActorMessageMeta& aMeta,
                                          const ClonedMessageData& aData);
   mozilla::ipc::IPCResult RecvDidEmbedBrowsingContext(
       dom::BrowsingContext* aContext);
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -57,16 +57,17 @@ EXPORTS.mozilla.dom += [
     'PermissionMessageUtils.h',
     'ReferrerInfoUtils.h',
     'RemoteWebProgress.h',
     'RemoteWebProgressRequest.h',
     'TabContext.h',
     'TabMessageUtils.h',
     'URLClassifierChild.h',
     'URLClassifierParent.h',
+    'WindowGlobalActor.h',
     'WindowGlobalChild.h',
     'WindowGlobalParent.h',
 ]
 
 EXPORTS.mozilla += [
     'PreallocatedProcessManager.h',
     'ProcessHangMonitor.h',
     'ProcessHangMonitorIPC.h',
@@ -101,16 +102,17 @@ UNIFIED_SOURCES += [
     'RemoteWebProgress.cpp',
     'RemoteWebProgressRequest.cpp',
     'SharedMap.cpp',
     'SharedStringMap.cpp',
     'StructuredCloneData.cpp',
     'TabContext.cpp',
     'TabMessageUtils.cpp',
     'URLClassifierParent.cpp',
+    'WindowGlobalActor.cpp',
     'WindowGlobalChild.cpp',
     'WindowGlobalParent.cpp',
 ]
 
 # ContentChild.cpp cannot be compiled in unified mode on  linux due to Time conflict
 SOURCES += [
     'ContentChild.cpp',
     'ProcessHangMonitor.cpp',