Bug 1583321 - Allow sending same entry multiple times during one IPC call. r=nika
authorPeter Van der Beken <peterv@propagandism.org>
Mon, 30 Sep 2019 15:25:53 +0200
changeset 500510 f24cad095172ebf36649a02a37dbdbbb3712f89c
parent 500509 325fca25e08dd2757735a17a8b8a6c7ce98f53ac
child 500511 dfd20e536b859a800d854a8bc69d4c84d60689e9
push id114165
push userpvanderbeken@mozilla.com
push dateWed, 06 Nov 2019 09:18:40 +0000
treeherdermozilla-inbound@db1ddab2985d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika
bugs1583321
milestone72.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 1583321 - Allow sending same entry multiple times during one IPC call. r=nika Differential Revision: https://phabricator.services.mozilla.com/D46935
docshell/shistory/MaybeNewPSHEntry.cpp
docshell/shistory/MaybeNewPSHEntry.h
docshell/shistory/NewPSHEntry.ipdlh
docshell/shistory/PSHEntry.ipdl
docshell/shistory/PSHistory.ipdl
docshell/shistory/SHEntryChild.cpp
docshell/shistory/SHEntryChild.h
docshell/shistory/SHEntryParent.cpp
docshell/shistory/SHEntryParent.h
docshell/shistory/SHistoryChild.cpp
docshell/shistory/SHistoryParent.cpp
docshell/shistory/SHistoryParent.h
docshell/shistory/moz.build
dom/ipc/PContent.ipdl
new file mode 100644
--- /dev/null
+++ b/docshell/shistory/MaybeNewPSHEntry.cpp
@@ -0,0 +1,78 @@
+/* -*- 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 "mozilla/dom/MaybeNewPSHEntry.h"
+#include "mozilla/dom/PContentParent.h"
+#include "mozilla/dom/SHEntryChild.h"
+#include "mozilla/dom/SHEntryParent.h"
+
+namespace mozilla {
+namespace ipc {
+
+template <>
+struct IPDLParamTraits<dom::NewPSHEntry> {
+  static void Write(IPC::Message* aMsg, IProtocol* aActor,
+                    dom::NewPSHEntry&& aEntry) {
+    MOZ_RELEASE_ASSERT(aActor->GetSide() == ParentSide, "wrong side!");
+
+    WriteIPDLParam(aMsg, aActor, std::move(aEntry.mEndpoint));
+    WriteIPDLParam(aMsg, aActor, aEntry.mSharedID);
+  }
+
+  static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
+                   IProtocol* aActor, dom::NewPSHEntry* aEntry) {
+    MOZ_RELEASE_ASSERT(aActor->GetSide() == ChildSide, "wrong side!");
+
+    return ReadIPDLParam(aMsg, aIter, aActor, &aEntry->mEndpoint) &&
+           ReadIPDLParam(aMsg, aIter, aActor, &aEntry->mSharedID);
+  }
+};
+
+/* static */
+void IPDLParamTraits<dom::CrossProcessSHEntry*>::Write(
+    IPC::Message* aMsg, IProtocol* aActor, dom::CrossProcessSHEntry* aEntry) {
+  MOZ_RELEASE_ASSERT(aActor->GetSide() == ParentSide, "wrong side!");
+  MOZ_DIAGNOSTIC_ASSERT(aActor->ToplevelProtocol()->GetProtocolId() ==
+                        PContentMsgStart);
+
+  dom::MaybeNewPSHEntryParent entry(static_cast<dom::PSHEntryParent*>(nullptr));
+  if (aEntry) {
+    entry = static_cast<dom::LegacySHEntry*>(aEntry)->GetOrCreateActor(
+        static_cast<dom::PContentParent*>(aActor->ToplevelProtocol()));
+  }
+
+  WriteIPDLParam(aMsg, aActor, std::move(entry));
+}
+
+/* static */
+bool IPDLParamTraits<dom::CrossProcessSHEntry*>::Read(
+    const IPC::Message* aMsg, PickleIterator* aIter,
+    mozilla::ipc::IProtocol* aActor, RefPtr<dom::CrossProcessSHEntry>* aEntry) {
+  MOZ_RELEASE_ASSERT(aActor->GetSide() == ChildSide, "wrong side!");
+
+  dom::MaybeNewPSHEntryChild actor(static_cast<dom::PSHEntryChild*>(nullptr));
+  if (!ReadIPDLParam(aMsg, aIter, aActor, &actor)) {
+    aActor->FatalError("Error deserializing MaybeNewPSHEntry");
+    return false;
+  }
+
+  return actor.match(
+      [&](dom::PSHEntryChild*& entry) {
+        *aEntry = static_cast<dom::SHEntryChild*>(entry);
+        return true;
+      },
+      [&](dom::NewPSHEntry& newEntry) {
+        RefPtr<dom::SHEntryChild> entry =
+            new dom::SHEntryChild(newEntry.mSharedID);
+        dom::ContentChild::GetSingleton()->BindPSHEntryEndpoint(
+            std::move(newEntry.mEndpoint), do_AddRef(entry).take());
+        *aEntry = entry.forget();
+        return true;
+      });
+}
+
+}  // namespace ipc
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/docshell/shistory/MaybeNewPSHEntry.h
@@ -0,0 +1,56 @@
+/* -*- 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_MaybeNewPSHEntry_h
+#define mozilla_dom_MaybeNewPSHEntry_h
+
+#include "ipc/IPCMessageUtils.h"
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/Variant.h"
+#include "mozilla/ipc/IPDLParamTraits.h"
+#include "mozilla/ipc/ProtocolUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+class LegacySHEntry;
+class PSHEntryChild;
+class PSHEntryParent;
+class SHEntryChild;
+
+struct NewPSHEntry final {
+  mozilla::ipc::ManagedEndpoint<PSHEntryChild> mEndpoint;
+  uint64_t mSharedID;
+};
+
+typedef Variant<PSHEntryParent*, NewPSHEntry> MaybeNewPSHEntryParent;
+typedef Variant<PSHEntryChild*, NewPSHEntry> MaybeNewPSHEntryChild;
+
+// Any IPDL protocol trying to pass this (as argument or return value) needs to
+// be managed by PContent.
+class CrossProcessSHEntry {
+  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
+
+  SHEntryChild* ToSHEntryChild();
+};
+
+}  // namespace dom
+
+namespace ipc {
+
+template <>
+struct IPDLParamTraits<dom::CrossProcessSHEntry*> {
+  static void Write(IPC::Message* aMsg, IProtocol* aActor,
+                    dom::CrossProcessSHEntry* aEntry);
+
+  static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
+                   IProtocol* aActor, RefPtr<dom::CrossProcessSHEntry>* aEntry);
+};
+
+}  // namespace ipc
+}  // namespace mozilla
+
+#endif /* mozilla_dom_MaybeNewPSHEntry_h */
deleted file mode 100644
--- a/docshell/shistory/NewPSHEntry.ipdlh
+++ /dev/null
@@ -1,27 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-include protocol PSHEntry;
-
-namespace mozilla {
-namespace dom {
-
-union PSHEntryOrSharedID
-{
-  PSHEntry;
-  uint64_t;
-};
-
-struct NewPSHEntry {
-  ManagedEndpoint<PSHEntryChild> endpoint;
-  uint64_t sharedID;
-};
-
-union MaybeNewPSHEntry {
-  nullable PSHEntry;
-  NewPSHEntry;
-};
-
-} // namespace dom
-} // namespace mozilla
--- a/docshell/shistory/PSHEntry.ipdl
+++ b/docshell/shistory/PSHEntry.ipdl
@@ -1,26 +1,28 @@
 /* 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 protocol PContent;
 include protocol PSHistory;
 
 include DOMTypes;
-include NewPSHEntry;
 
+using refcounted class mozilla::dom::CrossProcessSHEntry from "mozilla/dom/MaybeNewPSHEntry.h";
 using refcounted class nsDocShellLoadState from "mozilla/dom/DocShellMessageUtils.h";
 using struct nsID from "nsID.h";
 using nsIntRect from "nsRect.h";
 
 namespace mozilla {
 namespace dom {
 
 sync protocol PSHEntry {
+  // IPDLParamTraits<dom::CrossProcessSHEntry*>::Write relies on PContent being
+  // the manager.
   manager PContent;
 
 parent:
   sync GetURI() returns (nsIURI uri);
   async SetURI(nsIURI uri);
   sync GetOriginalURI() returns (nsIURI originalUri);
   async SetOriginalURI(nsIURI originalUri);
   sync GetResultPrincipalURI() returns (nsIURI resultPrincipalUri);
@@ -32,17 +34,17 @@ parent:
   sync GetIsSubFrame() returns (bool isSubFrame);
   async SetIsSubFrame(bool isSubFrame);
   sync GetReferrerInfo() returns (nsIReferrerInfo referrerInfo);
   async SetReferrerInfo(nsIReferrerInfo referrerInfo);
   sync GetSticky() returns (bool sticky);
   async SetSticky(bool sticky);
   sync GetPostData() returns (nsIInputStream postData);
   async SetPostData(nsIInputStream postData);
-  sync GetParent() returns (MaybeNewPSHEntry parentEntry);
+  sync GetParent() returns (CrossProcessSHEntry parentEntry);
   async SetParent(nullable PSHEntry parentEntry);
   sync GetLoadType() returns (uint32_t loadType);
   async SetLoadType(uint32_t loadType);
   sync GetID() returns (uint32_t id);
   async SetID(uint32_t id);
   sync GetCacheKey() returns (uint32_t cacheKey);
   async SetCacheKey(uint32_t cacheKey);
   sync GetExpirationStatus() returns (bool expirationStatus);
@@ -95,18 +97,18 @@ parent:
   sync HasDynamicallyAddedChild() returns (bool hasDynamicallyAddedChild);
   sync AdoptBFCacheEntry(PSHEntry entry) returns (nsresult result);
   async AbandonBFCacheEntry(uint64_t aNewSharedID);
   sync SharesDocumentWith(PSHEntry entry) returns (bool sharesDocumentWith,
                                                    nsresult result);
   async SetLoadTypeAsHistory();
   sync AddChild(nullable PSHEntry childEntry, int32_t offset, bool useRemoteSubframes) returns (nsresult result);
   sync RemoveChild(PSHEntry childEntry) returns (nsresult result);
-  sync GetChildAt(int32_t index) returns (MaybeNewPSHEntry childEntry);
-  sync GetChildSHEntryIfHasNoDynamicallyAddedChild(int32_t childOffset) returns (MaybeNewPSHEntry childEntry);
+  sync GetChildAt(int32_t index) returns (CrossProcessSHEntry childEntry);
+  sync GetChildSHEntryIfHasNoDynamicallyAddedChild(int32_t childOffset) returns (CrossProcessSHEntry childEntry);
   sync ReplaceChild(PSHEntry newChildEntry) returns (nsresult result);
   async ClearEntry(uint64_t aNewSharedID);
   sync CreateLoadInfo() returns (nsDocShellLoadState loadState);
 
   sync __delete__();
 };
 
 } // namespace dom
--- a/docshell/shistory/PSHistory.ipdl
+++ b/docshell/shistory/PSHistory.ipdl
@@ -1,65 +1,68 @@
 /* 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 protocol PContent;
 include protocol PSHEntry;
 
 include DOMTypes;
-include NewPSHEntry;
 
 using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h";
+using refcounted class mozilla::dom::CrossProcessSHEntry from "mozilla/dom/MaybeNewPSHEntry.h";
 using refcounted class nsDocShellLoadState from "mozilla/dom/DocShellMessageUtils.h";
 
 using struct nsID from "nsID.h";
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 struct LoadSHEntryData
 {
-  MaybeNewPSHEntry shEntry;
+  CrossProcessSHEntry shEntry;
   BrowsingContext browsingContext;
   nsDocShellLoadState loadState;
 };
 
 union LoadSHEntryResult {
   nsresult;
   LoadSHEntryData;
 };
 
 sync protocol PSHistory {
+  // IPDLParamTraits<dom::CrossProcessSHEntry*>::Write relies on PContent being
+  // the manager.
   manager PContent;
 
 parent:
   sync GetCount() returns (int32_t count);
   sync GetIndex() returns (int32_t index);
   sync SetIndex(int32_t index) returns (nsresult result);
   sync GetRequestedIndex() returns (int32_t index);
   async InternalSetRequestedIndex(int32_t index);
-  sync GetEntryAtIndex(int32_t index) returns (nsresult result, MaybeNewPSHEntry entry);
+  sync GetEntryAtIndex(int32_t index) returns (nsresult result, CrossProcessSHEntry entry);
   sync PurgeHistory(int32_t numEntries) returns (nsresult result);
   sync ReloadCurrentEntry() returns (LoadSHEntryResult load);
   sync GotoIndex(int32_t index) returns (LoadSHEntryResult load);
   sync GetIndexOfEntry(PSHEntry entry) returns (int32_t index);
   sync AddEntry(PSHEntry entry, bool persist) returns (nsresult result, int32_t entriesPurged);
   async UpdateIndex();
   sync ReplaceEntry(int32_t index, PSHEntry entry) returns (nsresult result);
   sync NotifyOnHistoryReload() returns (bool ok);
   async EvictOutOfRangeContentViewers(int32_t index);
   async EvictAllContentViewers();
   async RemoveDynEntries(int32_t index, PSHEntry entry);
   sync RemoveEntries(nsID[] ids, int32_t index) returns (bool didRemove);
   async RemoveFrameEntries(PSHEntry entry);
   sync Reload(uint32_t reloadFlags) returns (LoadSHEntryResult load);
-  sync GetAllEntries() returns (MaybeNewPSHEntry[] entries);
-  sync FindEntryForBFCache(uint64_t sharedID, bool includeCurrentEntry) returns (MaybeNewPSHEntry entries, int32_t startIndex);
+  sync GetAllEntries() returns (CrossProcessSHEntry[] entries);
+  sync FindEntryForBFCache(uint64_t sharedID, bool includeCurrentEntry)
+    returns (CrossProcessSHEntry entries, int32_t startIndex);
   async Evict(PSHEntry[] entry);
   async EnsureCorrectEntryAtCurrIndex(PSHEntry entry);
   async EvictContentViewersOrReplaceEntry(nullable PSHEntry newSHEntry, bool replace);
   async NotifyListenersContentViewerEvicted(uint32_t numEvicted);
   async __delete__();
 };
 
 } // namespace dom
--- a/docshell/shistory/SHEntryChild.cpp
+++ b/docshell/shistory/SHEntryChild.cpp
@@ -2,16 +2,18 @@
 /* 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 "SHEntryChild.h"
 #include "SHistoryChild.h"
 #include "mozilla/ClearOnShutdown.h"
+#include "mozilla/StaticPrefs_docshell.h"
+#include "mozilla/dom/MaybeNewPSHEntry.h"
 #include "nsDocShellEditorData.h"
 #include "nsDocShellLoadState.h"
 #include "nsIContentViewer.h"
 #include "nsILayoutHistoryState.h"
 #include "nsIMutableArray.h"
 #include "nsStructuredCloneContainer.h"
 
 namespace mozilla {
@@ -588,22 +590,22 @@ SHEntryChild::Clone(nsISHEntry** aResult
   NS_IF_ADDREF(*aResult = static_cast<SHEntryChild*>(
                    ContentChild::GetSingleton()->SendPSHEntryConstructor(
                        this)));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SHEntryChild::GetParent(nsISHEntry** aResult) {
-  MaybeNewPSHEntry parent;
+  RefPtr<CrossProcessSHEntry> parent;
   if (!SendGetParent(&parent)) {
     return NS_ERROR_FAILURE;
   }
 
-  *aResult = SHEntryChild::GetOrCreate(parent).take();
+  *aResult = parent ? do_AddRef(parent->ToSHEntryChild()).take() : nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SHEntryChild::SetParent(nsISHEntry* aParent) {
   return SendSetParent(static_cast<SHEntryChild*>(aParent)) ? NS_OK
                                                             : NS_ERROR_FAILURE;
 }
@@ -803,31 +805,31 @@ SHEntryChild::RemoveChild(nsISHEntry* aC
   nsresult rv;
   return aChild && SendRemoveChild(static_cast<SHEntryChild*>(aChild), &rv)
              ? rv
              : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 SHEntryChild::GetChildAt(int32_t aIndex, nsISHEntry** aResult) {
-  MaybeNewPSHEntry child;
+  RefPtr<CrossProcessSHEntry> child;
   if (!SendGetChildAt(aIndex, &child)) {
     return NS_ERROR_FAILURE;
   }
 
-  *aResult = SHEntryChild::GetOrCreate(child).take();
+  *aResult = child ? do_AddRef(child->ToSHEntryChild()).take() : nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP_(void)
 SHEntryChild::GetChildSHEntryIfHasNoDynamicallyAddedChild(int32_t aChildOffset,
                                                           nsISHEntry** aChild) {
-  MaybeNewPSHEntry child;
+  RefPtr<CrossProcessSHEntry> child;
   SendGetChildSHEntryIfHasNoDynamicallyAddedChild(aChildOffset, &child);
-  *aChild = SHEntryChild::GetOrCreate(child).take();
+  *aChild = child ? do_AddRef(child->ToSHEntryChild()).take() : nullptr;
 }
 
 NS_IMETHODIMP
 SHEntryChild::ReplaceChild(nsISHEntry* aNewEntry) {
   nsresult rv;
   return SendReplaceChild(static_cast<SHEntryChild*>(aNewEntry), &rv)
              ? rv
              : NS_ERROR_FAILURE;
@@ -1007,25 +1009,10 @@ void SHEntryChild::EvictContentViewer() 
     // document teardown is able to correctly persist the state.
     mShared->NotifyListenersContentViewerEvicted();
     SetContentViewer(nullptr);
     SyncPresentationState();
     viewer->Destroy();
   }
 }
 
-/* static */
-already_AddRefed<SHEntryChild> SHEntryChild::GetOrCreate(
-    MaybeNewPSHEntry& aEntry) {
-  RefPtr<SHEntryChild> entry;
-  if (aEntry.type() == MaybeNewPSHEntry::TNewPSHEntry) {
-    NewPSHEntry& newEntry = aEntry.get_NewPSHEntry();
-    entry = new SHEntryChild(newEntry.sharedID());
-    ContentChild::GetSingleton()->BindPSHEntryEndpoint(
-        std::move(newEntry.endpoint()), do_AddRef(entry).take());
-  } else {
-    entry = static_cast<SHEntryChild*>(aEntry.get_PSHEntryChild());
-  }
-  return entry.forget();
-}
-
 }  // namespace dom
 }  // namespace mozilla
--- a/docshell/shistory/SHEntryChild.h
+++ b/docshell/shistory/SHEntryChild.h
@@ -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/. */
 
 #ifndef mozilla_dom_SHEntryChild_h
 #define mozilla_dom_SHEntryChild_h
 
 #include "mozilla/dom/PSHEntryChild.h"
+#include "mozilla/dom/MaybeNewPSHEntry.h"
 #include "nsContentUtils.h"
 #include "nsExpirationTracker.h"
 #include "nsIBFCacheEntry.h"
 #include "nsISHEntry.h"
 #include "nsRect.h"
 #include "nsSHEntryShared.h"
 #include "nsStubMutationObserver.h"
 
@@ -79,41 +80,47 @@ class SHEntryChildShared final : public 
 
   uint64_t mID;
   RefPtr<SHistoryChild> mSHistory;
 };
 
 /**
  * Session history entry actor for the child process.
  */
-class SHEntryChild final : public PSHEntryChild, public nsISHEntry {
+class SHEntryChild final : public PSHEntryChild,
+                           public nsISHEntry,
+                           public CrossProcessSHEntry {
   friend class PSHEntryChild;
+  using PSHEntryChild::CrossProcessSHEntry;
 
  public:
   explicit SHEntryChild(const SHEntryChild* aClone)
       : mShared(aClone->mShared.get()), mIPCActorDeleted(false) {}
   explicit SHEntryChild(uint64_t aSharedID)
       : mShared(SHEntryChildShared::GetOrCreate(aSharedID)),
         mIPCActorDeleted(false) {}
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISHENTRY
 
   void EvictContentViewer();
 
-  static already_AddRefed<SHEntryChild> GetOrCreate(MaybeNewPSHEntry& aEntry);
-
  protected:
   void ActorDestroy(ActorDestroyReason aWhy) override {
     mIPCActorDeleted = true;
   }
 
  private:
   ~SHEntryChild() = default;
 
   RefPtr<SHEntryChildShared> mShared;
   bool mIPCActorDeleted;
 };
 
+inline SHEntryChild* CrossProcessSHEntry::ToSHEntryChild() {
+  MOZ_ASSERT(XRE_IsContentProcess(), "Wrong side!");
+  return static_cast<SHEntryChild*>(this);
+}
+
 }  // namespace dom
 }  // namespace mozilla
 
 #endif /* mozilla_dom_SHEntryChild_h */
--- a/docshell/shistory/SHEntryParent.cpp
+++ b/docshell/shistory/SHEntryParent.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 "SHEntryParent.h"
 #include "SHistoryParent.h"
 #include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/MaybeNewPSHEntry.h"
 #include "nsStructuredCloneContainer.h"
 
 namespace mozilla {
 namespace dom {
 
 SHEntrySharedParent::SHEntrySharedParent(PContentParent* aContentParent,
                                          uint64_t aSharedID)
     : SHEntrySharedParentState(aSharedID), mContentParent(aContentParent) {}
@@ -19,31 +20,32 @@ SHEntrySharedParent::SHEntrySharedParent
 void SHEntrySharedParent::Destroy() {
   if (mContentParent &&
       !static_cast<ContentParent*>(mContentParent.get())->IsDestroyed()) {
     Unused << mContentParent->SendDestroySHEntrySharedState(mID);
   }
   SHEntrySharedParentState::Destroy();
 }
 
+NS_IMPL_ISUPPORTS_INHERITED0(LegacySHEntry, nsSHEntry)
+
 SHEntryParent* LegacySHEntry::CreateActor() {
   MOZ_ASSERT(!mActor);
   mActor = new SHEntryParent(this);
   return mActor;
 }
 
-void LegacySHEntry::GetOrCreateActor(PContentParent* aContentParent,
-                                     MaybeNewPSHEntry& aEntry) {
-  if (!mActor) {
-    mActor = new SHEntryParent(this);
-    aEntry =
-        NewPSHEntry(aContentParent->OpenPSHEntryEndpoint(mActor), mShared->mID);
-  } else {
-    aEntry = mActor;
+MaybeNewPSHEntryParent LegacySHEntry::GetOrCreateActor(
+    PContentParent* aContentParent) {
+  if (mActor) {
+    return AsVariant(static_cast<PSHEntryParent*>(mActor));
   }
+
+  return AsVariant(NewPSHEntry{
+      aContentParent->OpenPSHEntryEndpoint(CreateActor()), mShared->mID});
 }
 
 void LegacySHEntry::AbandonBFCacheEntry(uint64_t aNewSharedID) {
   PContentParent* contentParent =
       static_cast<SHEntrySharedParent*>(mShared.get())->GetContentParent();
   RefPtr<SHEntrySharedParent> shared =
       new SHEntrySharedParent(contentParent, aNewSharedID);
   shared->CopyFrom(mShared);
@@ -151,19 +153,19 @@ bool SHEntryParent::RecvGetPostData(RefP
 }
 
 bool SHEntryParent::RecvSetPostData(nsIInputStream* aPostData) {
   DebugOnly<nsresult> rv = mEntry->SetPostData(aPostData);
   MOZ_ASSERT(NS_SUCCEEDED(rv), "Didn't expect this to fail.");
   return true;
 }
 
-bool SHEntryParent::RecvGetParent(MaybeNewPSHEntry* aParentEntry) {
+bool SHEntryParent::RecvGetParent(RefPtr<CrossProcessSHEntry>* aParentEntry) {
   nsCOMPtr<nsISHEntry> parent = mEntry->GetParent();
-  GetOrCreate(parent, aParentEntry);
+  *aParentEntry = parent.forget().downcast<LegacySHEntry>();
   return true;
 }
 
 bool SHEntryParent::RecvSetParent(PSHEntryParent* aParentEntry) {
   DebugOnly<nsresult> rv = mEntry->SetParent(
       aParentEntry ? static_cast<SHEntryParent*>(aParentEntry)->mEntry.get()
                    : nullptr);
   MOZ_ASSERT(NS_SUCCEEDED(rv), "Didn't expect this to fail.");
@@ -502,50 +504,41 @@ bool SHEntryParent::RecvAddChild(PSHEntr
 }
 
 bool SHEntryParent::RecvRemoveChild(PSHEntryParent* aChild, nsresult* aResult) {
   *aResult = mEntry->RemoveChild(static_cast<SHEntryParent*>(aChild)->mEntry);
   return true;
 }
 
 bool SHEntryParent::RecvGetChildAt(const int32_t& aIndex,
-                                   MaybeNewPSHEntry* aChild) {
+                                   RefPtr<CrossProcessSHEntry>* aChild) {
   nsCOMPtr<nsISHEntry> child;
   DebugOnly<nsresult> rv = mEntry->GetChildAt(aIndex, getter_AddRefs(child));
   MOZ_ASSERT(NS_SUCCEEDED(rv), "Didn't expect this to fail.");
 
-  GetOrCreate(child, aChild);
+  *aChild = child.forget().downcast<LegacySHEntry>();
   return true;
 }
 
 bool SHEntryParent::RecvGetChildSHEntryIfHasNoDynamicallyAddedChild(
-    const int32_t& aChildOffset, MaybeNewPSHEntry* aChild) {
+    const int32_t& aChildOffset, RefPtr<CrossProcessSHEntry>* aChild) {
   nsCOMPtr<nsISHEntry> child;
   mEntry->GetChildSHEntryIfHasNoDynamicallyAddedChild(aChildOffset,
                                                       getter_AddRefs(child));
-  GetOrCreate(child, aChild);
+  *aChild = child.forget().downcast<LegacySHEntry>();
   return true;
 }
 
 bool SHEntryParent::RecvReplaceChild(PSHEntryParent* aNewChild,
                                      nsresult* aResult) {
   *aResult =
       mEntry->ReplaceChild(static_cast<SHEntryParent*>(aNewChild)->mEntry);
   return true;
 }
 
-void SHEntryParent::GetOrCreate(PContentParent* aManager, nsISHEntry* aSHEntry,
-                                MaybeNewPSHEntry& aResult) {
-  if (aSHEntry) {
-    static_cast<LegacySHEntry*>(aSHEntry)->GetOrCreateActor(aManager, aResult);
-  } else {
-    aResult = (PSHEntryParent*)nullptr;
-  }
-}
-
 bool SHEntryParent::RecvClearEntry(const uint64_t& aNewSharedID) {
   mEntry->ClearEntry();
   mEntry->AbandonBFCacheEntry(aNewSharedID);
   return true;
 }
 
 bool SHEntryParent::RecvCreateLoadInfo(
     RefPtr<nsDocShellLoadState>* aLoadState) {
--- a/docshell/shistory/SHEntryParent.h
+++ b/docshell/shistory/SHEntryParent.h
@@ -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/. */
 
 #ifndef mozilla_dom_SHistoryEntry_h
 #define mozilla_dom_SHistoryEntry_h
 
 #include "mozilla/dom/PSHEntryParent.h"
+#include "mozilla/dom/MaybeNewPSHEntry.h"
 #include "mozilla/WeakPtr.h"
 #include "nsSHEntry.h"
 #include "nsSHEntryShared.h"
 
 namespace mozilla {
 namespace dom {
 
 class PContentParent;
@@ -36,40 +37,43 @@ class SHEntrySharedParent : public SHEnt
 
 /**
  * Session history entry implementation based on the legacy implementation that
  * used to live in the child process. Ideally this wouldn't implement nsISHEntry
  * (it should only ever be accessed by SHEntryParent and LegacySHistory).
  * The actor is (re)created as needed, whenever we need to return an entry to
  * the child process. The lifetime is determined by the child side.
  */
-class LegacySHEntry final : public nsSHEntry {
+class LegacySHEntry final : public nsSHEntry, public CrossProcessSHEntry {
  public:
   LegacySHEntry(PContentParent* aParent, uint64_t aSharedID)
       : nsSHEntry(new SHEntrySharedParent(aParent, aSharedID)),
         mActor(nullptr) {}
   explicit LegacySHEntry(const LegacySHEntry& aEntry)
       : nsSHEntry(aEntry), mActor(nullptr) {}
 
-  void GetOrCreateActor(PContentParent* aContentParent,
-                        MaybeNewPSHEntry& aEntry);
+  NS_DECL_ISUPPORTS_INHERITED
+
+  MaybeNewPSHEntryParent GetOrCreateActor(PContentParent* aContentParent);
 
   using nsSHEntry::AbandonBFCacheEntry;
   void AbandonBFCacheEntry(uint64_t aNewSharedID);
 
   uint64_t GetSharedStateID() const { return mShared->GetID(); }
 
   dom::SHEntrySharedParentState* GetSharedState() const {
     return mShared.get();
   }
 
  private:
   friend class SHEntryParent;
   friend class ContentParent;
 
+  ~LegacySHEntry() {}
+
   SHEntryParent* CreateActor();
 
   SHEntryParent* mActor;
 };
 
 /**
  * Session history entry actor for the parent process. Forwards to the legacy
  * implementation that used to live in the child process (see LegacySHEntry).
@@ -78,19 +82,16 @@ class SHEntryParent final : public PSHEn
   friend class PSHEntryParent;
   friend class SHistoryParent;
   friend class ContentParent;
 
  public:
   explicit SHEntryParent(LegacySHEntry* aEntry)
       : PSHEntryParent(), mEntry(aEntry) {}
 
-  static void GetOrCreate(PContentParent* aManager, nsISHEntry* aSHEntry,
-                          MaybeNewPSHEntry& aResult);
-
   LegacySHEntry* GetSHEntry() { return mEntry; }
 
  protected:
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
  private:
   bool RecvGetURI(RefPtr<nsIURI>* aURI);
   bool RecvSetURI(nsIURI* aURI);
@@ -105,17 +106,17 @@ class SHEntryParent final : public PSHEn
   bool RecvGetIsSubFrame(bool* aIsSubFrame);
   bool RecvSetIsSubFrame(const bool& aIsSubFrame);
   bool RecvGetReferrerInfo(RefPtr<nsIReferrerInfo>* aReferrerInfo);
   bool RecvSetReferrerInfo(nsIReferrerInfo* aReferrerInfo);
   bool RecvGetSticky(bool* aSticky);
   bool RecvSetSticky(const bool& aSticky);
   bool RecvGetPostData(RefPtr<nsIInputStream>* aPostData);
   bool RecvSetPostData(nsIInputStream* aPostData);
-  bool RecvGetParent(MaybeNewPSHEntry* aParentEntry);
+  bool RecvGetParent(RefPtr<CrossProcessSHEntry>* aParentEntry);
   bool RecvSetParent(PSHEntryParent* aParentEntry);
   bool RecvGetLoadType(uint32_t* aLoadType);
   bool RecvSetLoadType(const uint32_t& aLoadType);
   bool RecvGetID(uint32_t* aID);
   bool RecvSetID(const uint32_t& aID);
   bool RecvGetCacheKey(uint32_t* aCacheKey);
   bool RecvSetCacheKey(const uint32_t& aCacheKey);
   bool RecvGetExpirationStatus(bool* aExpirationStatus);
@@ -175,25 +176,23 @@ class SHEntryParent final : public PSHEn
   bool RecvAdoptBFCacheEntry(PSHEntryParent* aEntry, nsresult* aResult);
   bool RecvAbandonBFCacheEntry(const uint64_t& aNewSharedID);
   bool RecvSharesDocumentWith(PSHEntryParent* aEntry, bool* aSharesDocumentWith,
                               nsresult* aResult);
   bool RecvSetLoadTypeAsHistory();
   bool RecvAddChild(PSHEntryParent* aChild, const int32_t& aOffset,
                     const bool& aUseRemoteSubframes, nsresult* aResult);
   bool RecvRemoveChild(PSHEntryParent* aChild, nsresult* aResult);
-  bool RecvGetChildAt(const int32_t& aIndex, MaybeNewPSHEntry* aChild);
+  bool RecvGetChildAt(const int32_t& aIndex,
+                      RefPtr<CrossProcessSHEntry>* aChild);
   bool RecvGetChildSHEntryIfHasNoDynamicallyAddedChild(
-      const int32_t& aChildOffset, MaybeNewPSHEntry* aChild);
+      const int32_t& aChildOffset, RefPtr<CrossProcessSHEntry>* aChild);
   bool RecvReplaceChild(PSHEntryParent* aNewChild, nsresult* aResult);
   bool RecvClearEntry(const uint64_t& aNewSharedID);
 
-  void GetOrCreate(nsISHEntry* aSHEntry, MaybeNewPSHEntry* aResult) {
-    GetOrCreate(Manager(), aSHEntry, *aResult);
-  }
   bool RecvCreateLoadInfo(RefPtr<nsDocShellLoadState>* aLoadState);
 
   RefPtr<LegacySHEntry> mEntry;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
--- a/docshell/shistory/SHistoryChild.cpp
+++ b/docshell/shistory/SHistoryChild.cpp
@@ -90,26 +90,25 @@ SHistoryChild::GetRequestedIndex(int32_t
 NS_IMETHODIMP_(void)
 SHistoryChild::InternalSetRequestedIndex(int32_t aRequestedIndex) {
   SendInternalSetRequestedIndex(aRequestedIndex);
 }
 
 NS_IMETHODIMP
 SHistoryChild::GetEntryAtIndex(int32_t aIndex, nsISHEntry** aResult) {
   nsresult rv;
-  MaybeNewPSHEntry entry;
+  RefPtr<CrossProcessSHEntry> entry;
   if (!SendGetEntryAtIndex(aIndex, &rv, &entry)) {
     return NS_ERROR_FAILURE;
   }
-  RefPtr<SHEntryChild> child;
-  if (NS_SUCCEEDED(rv)) {
-    child = SHEntryChild::GetOrCreate(entry);
-  }
-  child.forget(aResult);
-  return rv;
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  *aResult = entry ? do_AddRef(entry->ToSHEntryChild()).take() : nullptr;
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 SHistoryChild::PurgeHistory(int32_t aNumEntries) {
   nsresult rv;
   if (!SendPurgeHistory(aNumEntries, &rv)) {
     return NS_ERROR_FAILURE;
   }
@@ -240,43 +239,43 @@ SHistoryChild::EvictOutOfRangeContentVie
   //       compare content viewers so we don't evict live content viewers).
   return SendEvictOutOfRangeContentViewers(aIndex) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 SHistoryChild::EvictExpiredContentViewerForEntry(nsIBFCacheEntry* aBFEntry) {
   SHEntryChildShared* shared = static_cast<SHEntryChildShared*>(aBFEntry);
 
-  MaybeNewPSHEntry entry;
+  RefPtr<CrossProcessSHEntry> entry;
   int32_t index;
   if (!SendFindEntryForBFCache(shared->GetID(), false, &entry, &index)) {
     return NS_ERROR_FAILURE;
   }
 
-  RefPtr<SHEntryChild> shEntry = SHEntryChild::GetOrCreate(entry);
-  if (shEntry) {
+  RefPtr<SHEntryChild> shEntry;
+  if (entry && (shEntry = entry->ToSHEntryChild())) {
     shEntry->EvictContentViewer();
     SendEvict(nsTArray<PSHEntryChild*>({shEntry.get()}));
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SHistoryChild::EvictAllContentViewers(void) {
-  nsTArray<MaybeNewPSHEntry> entries;
+  nsTArray<RefPtr<CrossProcessSHEntry>> entries;
   if (!SendGetAllEntries(&entries)) {
     return NS_ERROR_FAILURE;
   }
 
   // Keep a strong reference to all the entries, we're going to send the array
   // back to the parent!
   nsTArray<RefPtr<SHEntryChild>> shEntries(entries.Length());
-  for (MaybeNewPSHEntry& entry : entries) {
-    RefPtr<SHEntryChild> shEntry = SHEntryChild::GetOrCreate(entry);
+  for (RefPtr<CrossProcessSHEntry>& entry : entries) {
+    RefPtr<SHEntryChild> shEntry = entry->ToSHEntryChild();
     shEntry->EvictContentViewer();
     shEntries.AppendElement(shEntry.forget());
   }
 
   nsTArray<PSHEntryChild*> pshEntries;
   pshEntries.AppendElements(shEntries);
   SendEvict(pshEntries);
   return NS_OK;
@@ -313,26 +312,26 @@ SHistoryChild::RemoveDynEntries(int32_t 
 
 NS_IMETHODIMP_(void)
 SHistoryChild::EnsureCorrectEntryAtCurrIndex(nsISHEntry* aEntry) {
   SendEnsureCorrectEntryAtCurrIndex(static_cast<SHEntryChild*>(aEntry));
 }
 
 NS_IMETHODIMP_(void)
 SHistoryChild::RemoveDynEntriesForBFCacheEntry(nsIBFCacheEntry* aBFEntry) {
-  MaybeNewPSHEntry entry;
+  RefPtr<CrossProcessSHEntry> entry;
   int32_t index;
   if (!SendFindEntryForBFCache(
           static_cast<SHEntryChildShared*>(aBFEntry)->GetID(), true, &entry,
           &index)) {
     return;
   }
 
-  RefPtr<SHEntryChild> shEntry = SHEntryChild::GetOrCreate(entry);
-  if (shEntry) {
+  RefPtr<SHEntryChild> shEntry;
+  if (entry && (shEntry = entry->ToSHEntryChild())) {
     RemoveDynEntries(index, shEntry);
   }
 }
 
 NS_IMETHODIMP_(void)
 SHistoryChild::RemoveEntries(nsTArray<nsID>& aIDs, int32_t aStartIndex) {
   bool didRemove = false;
   if (SendRemoveEntries(aIDs, aStartIndex, &didRemove) && didRemove &&
@@ -359,17 +358,20 @@ SHistoryChild::Reload(uint32_t aReloadFl
 
   return LoadURI(loadResult);
 }
 
 nsresult SHistoryChild::LoadURI(LoadSHEntryData& aLoadData) {
   nsCOMPtr<nsIDocShell> docShell = aLoadData.browsingContext()->GetDocShell();
   NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
 
-  RefPtr<SHEntryChild> entry = SHEntryChild::GetOrCreate(aLoadData.shEntry());
+  RefPtr<SHEntryChild> entry;
+  if (aLoadData.shEntry()) {
+    entry = aLoadData.shEntry()->ToSHEntryChild();
+  }
 
   // FIXME Should this be sent through IPC?
   aLoadData.loadState()->SetSHEntry(entry);
   return docShell->LoadURI(aLoadData.loadState(), false);
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/docshell/shistory/SHistoryParent.cpp
+++ b/docshell/shistory/SHistoryParent.cpp
@@ -22,21 +22,19 @@ LegacySHistory::LegacySHistory(Canonical
   mIsRemote = true;
   aRootBC->SetSessionHistory(this);
 }
 
 static void FillInLoadResult(PContentParent* aManager, nsresult aRv,
                              const nsSHistory::LoadEntryResult& aLoadResult,
                              LoadSHEntryResult* aResult) {
   if (NS_SUCCEEDED(aRv)) {
-    MaybeNewPSHEntry entry;
-    static_cast<LegacySHEntry*>(aLoadResult.mLoadState->SHEntry())
-        ->GetOrCreateActor(aManager, entry);
-    *aResult = LoadSHEntryData(std::move(entry), aLoadResult.mBrowsingContext,
-                               aLoadResult.mLoadState);
+    *aResult = LoadSHEntryData(
+        static_cast<LegacySHEntry*>(aLoadResult.mLoadState->SHEntry()),
+        aLoadResult.mBrowsingContext, aLoadResult.mLoadState);
   } else {
     *aResult = aRv;
   }
 }
 
 SHistoryParent::SHistoryParent(CanonicalBrowsingContext* aContext)
     : mContext(aContext), mHistory(new LegacySHistory(aContext, nsID())) {}
 
@@ -62,37 +60,35 @@ bool SHistoryParent::RecvGetRequestedInd
 }
 
 bool SHistoryParent::RecvInternalSetRequestedIndex(int32_t aIndex) {
   mHistory->InternalSetRequestedIndex(aIndex);
   return true;
 }
 
 bool SHistoryParent::RecvGetEntryAtIndex(int32_t aIndex, nsresult* aResult,
-                                         MaybeNewPSHEntry* aEntry) {
+                                         RefPtr<CrossProcessSHEntry>* aEntry) {
   nsCOMPtr<nsISHEntry> entry;
   *aResult = mHistory->GetEntryAtIndex(aIndex, getter_AddRefs(entry));
-  SHEntryParent::GetOrCreate(Manager(), entry, *aEntry);
+  *aEntry = entry.forget().downcast<LegacySHEntry>();
   return true;
 }
 
 bool SHistoryParent::RecvPurgeHistory(int32_t aNumEntries, nsresult* aResult) {
   *aResult = mHistory->PurgeHistory(aNumEntries);
   return true;
 }
 
 bool SHistoryParent::RecvReloadCurrentEntry(LoadSHEntryResult* aLoadResult) {
   nsSHistory::LoadEntryResult loadResult;
   nsresult rv = mHistory->ReloadCurrentEntry(loadResult);
   if (NS_SUCCEEDED(rv)) {
-    MaybeNewPSHEntry entry;
-    SHEntryParent::GetOrCreate(Manager(), loadResult.mLoadState->SHEntry(),
-                               entry);
     *aLoadResult = LoadSHEntryData(
-        std::move(entry), loadResult.mBrowsingContext, loadResult.mLoadState);
+        static_cast<LegacySHEntry*>(loadResult.mLoadState->SHEntry()),
+        loadResult.mBrowsingContext, loadResult.mLoadState);
   } else {
     *aLoadResult = rv;
   }
   return true;
 }
 
 bool SHistoryParent::RecvGotoIndex(int32_t aIndex,
                                    LoadSHEntryResult* aLoadResult) {
@@ -180,54 +176,53 @@ bool SHistoryParent::RecvRemoveFrameEntr
 bool SHistoryParent::RecvReload(const uint32_t& aReloadFlags,
                                 LoadSHEntryResult* aLoadResult) {
   nsSHistory::LoadEntryResult loadResult;
   nsresult rv = mHistory->Reload(aReloadFlags, loadResult);
   FillInLoadResult(Manager(), rv, loadResult, aLoadResult);
   return true;
 }
 
-bool SHistoryParent::RecvGetAllEntries(nsTArray<MaybeNewPSHEntry>* aEntries) {
+bool SHistoryParent::RecvGetAllEntries(
+    nsTArray<RefPtr<CrossProcessSHEntry>>* aEntries) {
   nsTArray<nsCOMPtr<nsISHEntry>>& entries = mHistory->Entries();
   uint32_t length = entries.Length();
   aEntries->AppendElements(length);
   for (uint32_t i = 0; i < length; ++i) {
-    SHEntryParent::GetOrCreate(Manager(), entries[i].get(),
-                               aEntries->ElementAt(i));
+    aEntries->ElementAt(i) = static_cast<LegacySHEntry*>(entries[i].get());
   }
   return true;
 }
 
-bool SHistoryParent::RecvFindEntryForBFCache(const uint64_t& aSharedID,
-                                             const bool& aIncludeCurrentEntry,
-                                             MaybeNewPSHEntry* aEntry,
-                                             int32_t* aIndex) {
+bool SHistoryParent::RecvFindEntryForBFCache(
+    const uint64_t& aSharedID, const bool& aIncludeCurrentEntry,
+    RefPtr<CrossProcessSHEntry>* aEntry, int32_t* aIndex) {
   int32_t currentIndex;
   mHistory->GetIndex(&currentIndex);
   int32_t startSafeIndex, endSafeIndex;
   mHistory->WindowIndices(currentIndex, &startSafeIndex, &endSafeIndex);
   for (int32_t i = startSafeIndex; i <= endSafeIndex; ++i) {
     nsCOMPtr<nsISHEntry> entry;
     nsresult rv = mHistory->GetEntryAtIndex(i, getter_AddRefs(entry));
     NS_ENSURE_SUCCESS(rv, false);
 
-    if (static_cast<LegacySHEntry*>(entry.get())->GetSharedStateID() ==
-        aSharedID) {
+    RefPtr<LegacySHEntry> shEntry = entry.forget().downcast<LegacySHEntry>();
+    if (shEntry->GetSharedStateID() == aSharedID) {
       if (!aIncludeCurrentEntry && i == currentIndex) {
-        *aEntry = (PSHEntryParent*)nullptr;
+        *aEntry = nullptr;
         *aIndex = -1;
       } else {
-        SHEntryParent::GetOrCreate(Manager(), entry, *aEntry);
+        *aEntry = shEntry.forget();
         *aIndex = i;
       }
 
       return true;
     }
   }
-  *aEntry = (PSHEntryParent*)nullptr;
+  *aEntry = nullptr;
   *aIndex = -1;
   return true;
 }
 
 bool SHistoryParent::RecvEvict(nsTArray<PSHEntryParent*>&& aEntries) {
   for (PSHEntryParent* entry : aEntries) {
     int32_t index =
         mHistory->GetIndexOfEntry(static_cast<SHEntryParent*>(entry)->mEntry);
--- a/docshell/shistory/SHistoryParent.h
+++ b/docshell/shistory/SHistoryParent.h
@@ -50,17 +50,17 @@ class SHistoryParent final : public PSHi
 
  private:
   bool RecvGetCount(int32_t* aCount);
   bool RecvGetIndex(int32_t* aIndex);
   bool RecvSetIndex(int32_t aIndex, nsresult* aResult);
   bool RecvGetRequestedIndex(int32_t* aIndex);
   bool RecvInternalSetRequestedIndex(int32_t aIndex);
   bool RecvGetEntryAtIndex(int32_t aIndex, nsresult* aResult,
-                           MaybeNewPSHEntry* aEntry);
+                           RefPtr<CrossProcessSHEntry>* aEntry);
   bool RecvPurgeHistory(int32_t aNumEntries, nsresult* aResult);
   bool RecvReloadCurrentEntry(LoadSHEntryResult* aLoadResult);
   bool RecvGotoIndex(int32_t aIndex, LoadSHEntryResult* aLoadResult);
   bool RecvGetIndexOfEntry(PSHEntryParent* aEntry, int32_t* aIndex);
   bool RecvAddEntry(PSHEntryParent* aEntry, bool aPersist, nsresult* aResult,
                     int32_t* aEntriesPurged);
   bool RecvUpdateIndex();
   bool RecvReplaceEntry(int32_t aIndex, PSHEntryParent* aEntry,
@@ -68,20 +68,21 @@ class SHistoryParent final : public PSHi
   bool RecvNotifyOnHistoryReload(bool* aOk);
   bool RecvEvictOutOfRangeContentViewers(int32_t aIndex);
   bool RecvEvictAllContentViewers();
   bool RecvRemoveDynEntries(int32_t aIndex, PSHEntryParent* aEntry);
   bool RecvRemoveEntries(nsTArray<nsID>&& ids, int32_t aIndex,
                          bool* aDidRemove);
   bool RecvRemoveFrameEntries(PSHEntryParent* aEntry);
   bool RecvReload(const uint32_t& aReloadFlags, LoadSHEntryResult* aLoadResult);
-  bool RecvGetAllEntries(nsTArray<MaybeNewPSHEntry>* aEntries);
+  bool RecvGetAllEntries(nsTArray<RefPtr<CrossProcessSHEntry>>* aEntries);
   bool RecvFindEntryForBFCache(const uint64_t& aSharedID,
                                const bool& aIncludeCurrentEntry,
-                               MaybeNewPSHEntry* aEntry, int32_t* aIndex);
+                               RefPtr<CrossProcessSHEntry>* aEntry,
+                               int32_t* aIndex);
   bool RecvEvict(nsTArray<PSHEntryParent*>&& aEntries);
   bool RecvEnsureCorrectEntryAtCurrIndex(PSHEntryParent* aEntry);
   bool RecvEvictContentViewersOrReplaceEntry(PSHEntryParent* aNewSHEntry,
                                              bool aReplace);
   bool RecvNotifyListenersContentViewerEvicted(uint32_t aNumEvicted);
 
   RefPtr<CanonicalBrowsingContext> mContext;
   RefPtr<LegacySHistory> mHistory;
--- a/docshell/shistory/moz.build
+++ b/docshell/shistory/moz.build
@@ -9,38 +9,39 @@ XPIDL_SOURCES += [
     'nsISHEntry.idl',
     'nsISHistory.idl',
     'nsISHistoryListener.idl',
 ]
 
 XPIDL_MODULE = 'shistory'
 
 IPDL_SOURCES += [
-    'NewPSHEntry.ipdlh',
     'PSHEntry.ipdl',
     'PSHistory.ipdl',
 ]
 
 EXPORTS += [
     'nsSHEntry.h',
     'nsSHEntryShared.h',
     'nsSHistory.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'ChildSHistory.h',
+    'MaybeNewPSHEntry.h',
     'ParentSHistory.h',
     'SHEntryChild.h',
     'SHEntryParent.h',
     'SHistoryChild.h',
     'SHistoryParent.h',
 ]
 
 UNIFIED_SOURCES += [
     'ChildSHistory.cpp',
+    'MaybeNewPSHEntry.cpp',
     'nsSHEntry.cpp',
     'nsSHEntryShared.cpp',
     'nsSHistory.cpp',
     'ParentSHistory.cpp',
     'SHEntryChild.cpp',
     'SHEntryParent.cpp',
     'SHistoryChild.cpp',
     'SHistoryParent.cpp',
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -61,17 +61,16 @@ include PBackgroundSharedTypes;
 include PContentPermission;
 include ServiceWorkerConfiguration;
 include GraphicsMessages;
 include MemoryReportTypes;
 include ClientIPCTypes;
 include HangTypes;
 include PrefsTypes;
 include NeckoChannelParams;
-include NewPSHEntry;
 
 #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
 include protocol PSandboxTesting;
 #endif
 
 using refcounted class nsIDOMGeoPosition from "nsGeoPositionIPCSerialiser.h";
 using refcounted class nsIAlertNotification from "mozilla/AlertNotificationIPCSerializer.h";
 
@@ -327,16 +326,22 @@ struct PostMessageData
     nsString targetOrigin;
     nsIURI targetOriginURI;
     nsIPrincipal callerPrincipal;
     nsIPrincipal subjectPrincipal;
     nsIURI callerDocumentURI;
     bool isFromPrivateWindow;
 };
 
+union PSHEntryOrSharedID
+{
+  PSHEntry;
+  uint64_t;
+};
+
 /**
  * The PContent protocol is a top-level protocol between the UI process
  * and a content process. There is exactly one PContentParent/PContentChild pair
  * for each content process.
  */
 nested(upto inside_cpow) sync protocol PContent
 {
     manages PBrowser;