Bug 1588491 - Associate session history entries with a session history object from creation. Continue to allow docshells to create session history entries even if the root docshell doesn't have a session history object. r=smaug
authorPeter Van der Beken <peterv@propagandism.org>
Thu, 24 Oct 2019 09:17:19 +0200
changeset 500514 13da9115c96bb79d33ff7bb56a170c9834157bf6
parent 500513 9a60f8caece89baa705f4f54862eff3b996a6b22
child 500515 fcbaebf2501b8acd8ddcb54c71a511bd52fb0615
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)
reviewerssmaug
bugs1588491
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 1588491 - Associate session history entries with a session history object from creation. Continue to allow docshells to create session history entries even if the root docshell doesn't have a session history object. r=smaug Differential Revision: https://phabricator.services.mozilla.com/D50574
docshell/base/nsDocShell.cpp
docshell/shistory/ChildSHistory.cpp
docshell/shistory/ChildSHistory.h
docshell/shistory/MaybeNewPSHEntry.cpp
docshell/shistory/MaybeNewPSHEntry.h
docshell/shistory/SHEntryChild.cpp
docshell/shistory/SHEntryChild.h
docshell/shistory/SHEntryParent.cpp
docshell/shistory/SHistoryParent.cpp
docshell/shistory/SHistoryParent.h
docshell/shistory/nsSHEntry.cpp
docshell/shistory/nsSHEntry.h
docshell/shistory/nsSHEntryShared.cpp
docshell/shistory/nsSHEntryShared.h
dom/ipc/ContentChild.cpp
dom/ipc/PContent.ipdl
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -11328,23 +11328,19 @@ nsresult nsDocShell::AddToSessionHistory
   }
 
   // Create a new entry if necessary.
   if (!entry) {
     nsCOMPtr<nsIWebNavigation> webnav = do_QueryInterface(root);
     NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
 
     RefPtr<ChildSHistory> shistory = webnav->GetSessionHistory();
-    NS_ENSURE_TRUE(shistory, NS_ERROR_FAILURE);
-
-    shistory->LegacySHistory()->CreateEntry(getter_AddRefs(entry));
-
-    if (!entry) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
+    entry = CreateSHEntryForDocShell(shistory ? shistory->LegacySHistory()
+                                              : nullptr);
+    NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE);
   }
 
   // Get the post data & referrer
   nsCOMPtr<nsIInputStream> inputStream;
   nsCOMPtr<nsIURI> originalURI;
   nsCOMPtr<nsIURI> resultPrincipalURI;
   bool loadReplace = false;
   nsCOMPtr<nsIReferrerInfo> referrerInfo;
--- a/docshell/shistory/ChildSHistory.cpp
+++ b/docshell/shistory/ChildSHistory.cpp
@@ -120,10 +120,22 @@ nsISupports* ChildSHistory::GetParentObj
   RefPtr<ContentFrameMessageManager> mm;
   if (mDocShell) {
     mm = mDocShell->GetMessageManager();
   }
   // else we must be unlinked... can that happen here?
   return ToSupports(mm);
 }
 
+already_AddRefed<nsISHEntry> CreateSHEntryForDocShell(nsISHistory* aSHistory) {
+  uint64_t sharedID = SHEntryChildShared::CreateSharedID();
+  if (XRE_IsContentProcess() && StaticPrefs::fission_sessionHistoryInParent()) {
+    return do_AddRef(static_cast<SHEntryChild*>(
+        ContentChild::GetSingleton()->SendPSHEntryConstructor(
+            static_cast<SHistoryChild*>(aSHistory), sharedID)));
+  }
+
+  nsCOMPtr<nsISHEntry> entry = new nsLegacySHEntry(aSHistory, sharedID);
+  return entry.forget();
+}
+
 }  // namespace dom
 }  // namespace mozilla
--- a/docshell/shistory/ChildSHistory.h
+++ b/docshell/shistory/ChildSHistory.h
@@ -103,12 +103,14 @@ class ChildSHistory : public nsISupports
     int32_t mOffset;
   };
 
   RefPtr<nsDocShell> mDocShell;
   nsCOMPtr<nsISHistory> mHistory;
   mozilla::LinkedList<PendingAsyncHistoryNavigation> mPendingNavigations;
 };
 
+already_AddRefed<nsISHEntry> CreateSHEntryForDocShell(nsISHistory* aSHistory);
+
 }  // namespace dom
 }  // namespace mozilla
 
 #endif /* mozilla_dom_ChildSHistory_h */
--- a/docshell/shistory/MaybeNewPSHEntry.cpp
+++ b/docshell/shistory/MaybeNewPSHEntry.cpp
@@ -14,24 +14,26 @@ 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.mSHistoryParent);
     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->mSHistoryChild) &&
            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!");
@@ -60,18 +62,19 @@ bool IPDLParamTraits<dom::CrossProcessSH
   }
 
   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);
+        RefPtr<dom::SHEntryChild> entry = new dom::SHEntryChild(
+            static_cast<dom::SHistoryChild*>(newEntry.mSHistoryChild),
+            newEntry.mSharedID);
         dom::ContentChild::GetSingleton()->BindPSHEntryEndpoint(
             std::move(newEntry.mEndpoint), do_AddRef(entry).take());
         *aEntry = entry.forget();
         return true;
       });
 }
 
 }  // namespace ipc
--- a/docshell/shistory/MaybeNewPSHEntry.h
+++ b/docshell/shistory/MaybeNewPSHEntry.h
@@ -18,16 +18,18 @@ namespace dom {
 
 class LegacySHEntry;
 class PSHEntryChild;
 class PSHEntryParent;
 class SHEntryChild;
 
 struct NewPSHEntry final {
   mozilla::ipc::ManagedEndpoint<PSHEntryChild> mEndpoint;
+  PSHistoryParent* mSHistoryParent;
+  PSHistoryChild* mSHistoryChild;
   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.
--- a/docshell/shistory/SHEntryChild.cpp
+++ b/docshell/shistory/SHEntryChild.cpp
@@ -27,24 +27,25 @@ uint64_t SHEntryChildShared::sNextShared
 /* static */
 void SHEntryChildShared::Init() {
   sSHEntryChildSharedTable =
       new nsRefPtrHashtable<nsUint64HashKey, SHEntryChildShared>();
   ClearOnShutdown(&sSHEntryChildSharedTable);
 }
 
 /* static */
-SHEntryChildShared* SHEntryChildShared::GetOrCreate(uint64_t aSharedID) {
+SHEntryChildShared* SHEntryChildShared::GetOrCreate(SHistoryChild* aSHistory,
+                                                    uint64_t aSharedID) {
   MOZ_DIAGNOSTIC_ASSERT(
       sSHEntryChildSharedTable,
       "SHEntryChildShared::Init should have created the table.");
   RefPtr<SHEntryChildShared>& shared =
       sSHEntryChildSharedTable->GetOrInsert(aSharedID);
   if (!shared) {
-    shared = new SHEntryChildShared(aSharedID);
+    shared = new SHEntryChildShared(aSHistory, aSharedID);
   }
   return shared;
 }
 
 void SHEntryChildShared::Remove(uint64_t aSharedID) {
   if (sSHEntryChildSharedTable) {
     sSHEntryChildSharedTable->Remove(aSharedID);
   }
@@ -76,17 +77,18 @@ void SHEntryChildShared::EvictContentVie
       // This is the last shared object, so we should notify our
       // listeners about any content viewers that were evicted.
       // It does not matter which shared entry we will use for notifying.
       shared->NotifyListenersContentViewerEvicted(numEvictedSoFar);
     }
   }
 }
 
-SHEntryChildShared::SHEntryChildShared(uint64_t aID) : mID(aID) {}
+SHEntryChildShared::SHEntryChildShared(SHistoryChild* aSHistory, uint64_t aID)
+    : mID(aID), mSHistory(aSHistory) {}
 
 SHEntryChildShared::~SHEntryChildShared() {
   // The destruction can be caused by either the entry is removed from session
   // history and no one holds the reference, or the whole session history is on
   // destruction. We want to ensure that we invoke
   // shistory->RemoveFromExpirationTracker for the former case.
   RemoveFromExpirationTracker();
 
@@ -100,17 +102,17 @@ SHEntryChildShared::~SHEntryChildShared(
     RemoveFromBFCacheSync();
   }
 }
 
 NS_IMPL_ISUPPORTS(SHEntryChildShared, nsIBFCacheEntry, nsIMutationObserver)
 
 already_AddRefed<SHEntryChildShared> SHEntryChildShared::Duplicate() {
   RefPtr<SHEntryChildShared> newEntry = new SHEntryChildShared(
-      mozilla::dom::SHEntryChildShared::CreateSharedID());
+      mSHistory, mozilla::dom::SHEntryChildShared::CreateSharedID());
   newEntry->CopyFrom(this);
   return newEntry.forget();
 }
 
 void SHEntryChildShared::RemoveFromExpirationTracker() {
   if (mSHistory && GetExpirationState()->IsTracked()) {
     mSHistory->RemoveFromExpirationTracker(this);
   }
--- a/docshell/shistory/SHEntryChild.h
+++ b/docshell/shistory/SHEntryChild.h
@@ -32,17 +32,18 @@ class SHistoryChild;
  * process.
  */
 class SHEntryChildShared final : public nsIBFCacheEntry,
                                  public nsStubMutationObserver,
                                  public SHEntrySharedChildState {
  public:
   static void Init();
 
-  static SHEntryChildShared* GetOrCreate(uint64_t aSharedID);
+  static SHEntryChildShared* GetOrCreate(SHistoryChild* aSHistory,
+                                         uint64_t aSharedID);
   static void Remove(uint64_t aSharedID);
 
   static uint64_t CreateSharedID() {
     return nsContentUtils::GenerateProcessSpecificId(++sNextSharedID);
   }
   static void EvictContentViewers(
       const nsTArray<uint64_t>& aToEvictSharedStateIDs);
 
@@ -60,17 +61,17 @@ class SHEntryChildShared final : public 
 
   nsExpirationState* GetExpirationState() { return &mExpirationState; }
 
   uint64_t GetID() { return mID; }
 
  private:
   static uint64_t sNextSharedID;
 
-  explicit SHEntryChildShared(uint64_t aID);
+  SHEntryChildShared(SHistoryChild* aSHistory, uint64_t aID);
   ~SHEntryChildShared();
 
   friend class SHEntryChild;
 
   already_AddRefed<SHEntryChildShared> Duplicate();
 
   void RemoveFromExpirationTracker();
   void SyncPresentationState();
@@ -89,18 +90,18 @@ class SHEntryChild final : public PSHEnt
                            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)),
+  SHEntryChild(SHistoryChild* aSHistory, uint64_t aSharedID)
+      : mShared(SHEntryChildShared::GetOrCreate(aSHistory, aSharedID)),
         mIPCActorDeleted(false) {}
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISHENTRY
 
   void EvictContentViewer();
 
  protected:
--- a/docshell/shistory/SHEntryParent.cpp
+++ b/docshell/shistory/SHEntryParent.cpp
@@ -41,18 +41,21 @@ SHEntryParent* LegacySHEntry::CreateActo
 }
 
 MaybeNewPSHEntryParent LegacySHEntry::GetOrCreateActor(
     PContentParent* aContentParent) {
   if (mActor) {
     return AsVariant(static_cast<PSHEntryParent*>(mActor));
   }
 
-  return AsVariant(NewPSHEntry{
-      aContentParent->OpenPSHEntryEndpoint(CreateActor()), mShared->mID});
+  nsCOMPtr<nsISHistory> shistory = do_QueryReferent(mShared->mSHistory);
+  return AsVariant(
+      NewPSHEntry{aContentParent->OpenPSHEntryEndpoint(CreateActor()),
+                  static_cast<LegacySHistory*>(shistory.get())->GetActor(),
+                  nullptr, mShared->mID});
 }
 
 void LegacySHEntry::AbandonBFCacheEntry(uint64_t aNewSharedID) {
   mShared =
       static_cast<SHEntrySharedParent*>(mShared.get())->Duplicate(aNewSharedID);
 }
 
 NS_IMETHODIMP
--- a/docshell/shistory/SHistoryParent.cpp
+++ b/docshell/shistory/SHistoryParent.cpp
@@ -11,19 +11,20 @@
 #include "nsTHashtable.h"
 #include "mozilla/Logging.h"
 
 extern mozilla::LazyLogModule gSHistoryLog;
 
 namespace mozilla {
 namespace dom {
 
-LegacySHistory::LegacySHistory(CanonicalBrowsingContext* aRootBC,
+LegacySHistory::LegacySHistory(SHistoryParent* aSHistoryParent,
+                               CanonicalBrowsingContext* aRootBC,
                                const nsID& aDocShellID)
-    : nsSHistory(aRootBC, aDocShellID) {
+    : nsSHistory(aRootBC, aDocShellID), mSHistoryParent(aSHistoryParent) {
   mIsRemote = true;
   aRootBC->SetSessionHistory(this);
 }
 
 static void FillInLoadResult(PContentParent* aManager, nsresult aRv,
                              const nsSHistory::LoadEntryResult& aLoadResult,
                              LoadSHEntryResult* aResult) {
   if (NS_SUCCEEDED(aRv)) {
@@ -31,19 +32,19 @@ static void FillInLoadResult(PContentPar
         static_cast<LegacySHEntry*>(aLoadResult.mLoadState->SHEntry()),
         aLoadResult.mBrowsingContext, aLoadResult.mLoadState);
   } else {
     *aResult = aRv;
   }
 }
 
 SHistoryParent::SHistoryParent(CanonicalBrowsingContext* aContext)
-    : mHistory(new LegacySHistory(aContext, nsID())) {}
+    : mHistory(new LegacySHistory(this, aContext, nsID())) {}
 
-SHistoryParent::~SHistoryParent() {}
+SHistoryParent::~SHistoryParent() { mHistory->mSHistoryParent = nullptr; }
 
 SHEntryParent* SHistoryParent::CreateEntry(
     PContentParent* aContentParent, PSHistoryParent* aSHistoryParent,
     const PSHEntryOrSharedID& aEntryOrSharedID) {
   RefPtr<LegacySHEntry> entry;
   if (aEntryOrSharedID.type() == PSHEntryOrSharedID::Tuint64_t) {
     entry = new LegacySHEntry(
         aContentParent, static_cast<SHistoryParent*>(aSHistoryParent)->mHistory,
--- a/docshell/shistory/SHistoryParent.h
+++ b/docshell/shistory/SHistoryParent.h
@@ -19,31 +19,38 @@ class SHistoryParent;
 
 /**
  * Session history implementation based on the legacy implementation that used
  * to live in the child process. Ideally this wouldn't implement nsISHistory
  * (it should only ever be accessed by SHistoryParent).
  */
 class LegacySHistory final : public nsSHistory {
  private:
+  friend class SHistoryParent;
   virtual ~LegacySHistory() {}
 
   void EvictOutOfRangeWindowContentViewers(int32_t aIndex) override;
 
+  SHistoryParent* mSHistoryParent;
+
  public:
-  LegacySHistory(CanonicalBrowsingContext* aRootBC, const nsID& aDocShellID);
+  LegacySHistory(SHistoryParent* aSHistoryParent,
+                 CanonicalBrowsingContext* aRootBC, const nsID& aDocShellID);
 
   NS_IMETHOD CreateEntry(nsISHEntry** aEntry) override;
+
+  SHistoryParent* GetActor() { return mSHistoryParent; }
 };
 
 /**
  * Session history actor for the parent process. Forwards to the legacy
  * implementation that used to live in the child process (see LegacySHistory).
  */
 class SHistoryParent final : public PSHistoryParent {
+  friend class LegacySHistory;
   friend class PSHistoryParent;
   friend class SHEntryParent;
 
  public:
   explicit SHistoryParent(CanonicalBrowsingContext* aContext);
   virtual ~SHistoryParent();
 
   static SHEntryParent* CreateEntry(PContentParent* aContentParent,
--- a/docshell/shistory/nsSHEntry.cpp
+++ b/docshell/shistory/nsSHEntry.cpp
@@ -1033,17 +1033,17 @@ void nsSHEntry::EvictContentViewer() {
     // Drop the presentation state before destroying the viewer, so that
     // document teardown is able to correctly persist the state.
     SetContentViewer(nullptr);
     SyncPresentationState();
     viewer->Destroy();
   }
 }
 
-nsLegacySHEntry::nsLegacySHEntry(nsSHistory* aHistory, uint64_t aID)
+nsLegacySHEntry::nsLegacySHEntry(nsISHistory* aHistory, uint64_t aID)
     : nsSHEntry(new nsSHEntryShared(aHistory, aID)) {}
 
 NS_IMETHODIMP
 nsLegacySHEntry::SetContentViewer(nsIContentViewer* aViewer) {
   return GetState()->SetContentViewer(aViewer);
 }
 
 NS_IMETHODIMP
--- a/docshell/shistory/nsSHEntry.h
+++ b/docshell/shistory/nsSHEntry.h
@@ -74,17 +74,17 @@ class nsSHEntry : public nsISHEntry {
 /**
  * Session history entry class used for implementing session history for
  * docshells in the parent process (a different solution would be to use the
  * IPC actors for that too, with both parent and child actor created in the
  * parent process).
  */
 class nsLegacySHEntry final : public nsSHEntry {
  public:
-  explicit nsLegacySHEntry(nsSHistory* aHistory, uint64_t aID);
+  explicit nsLegacySHEntry(nsISHistory* aHistory, uint64_t aID);
   explicit nsLegacySHEntry(const nsLegacySHEntry& aOther) : nsSHEntry(aOther) {}
 
   NS_IMETHOD GetContentViewer(nsIContentViewer** aResult) override;
   NS_IMETHOD SetContentViewer(nsIContentViewer* aViewer) override;
   NS_IMETHOD GetWindowState(nsISupports** aState) override;
   NS_IMETHOD SetWindowState(nsISupports* aState) override;
   using nsISHEntry::GetRefreshURIList;
   NS_IMETHOD GetRefreshURIList(nsIMutableArray** aRefreshURIList) override;
--- a/docshell/shistory/nsSHEntryShared.cpp
+++ b/docshell/shistory/nsSHEntryShared.cpp
@@ -20,17 +20,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/Preferences.h"
 
 namespace dom = mozilla::dom;
 
 namespace mozilla {
 namespace dom {
 
-SHEntrySharedParentState::SHEntrySharedParentState(nsSHistory* aSHistory,
+SHEntrySharedParentState::SHEntrySharedParentState(nsISHistory* aSHistory,
                                                    uint64_t aID)
     : SHEntrySharedParentState(nsWeakPtr(do_GetWeakReference(aSHistory)).get(),
                                aID) {}
 
 SHEntrySharedParentState::SHEntrySharedParentState(nsIWeakReference* aSHistory,
                                                    uint64_t aID)
     : mDocShellID({0}),
       mViewerBounds(0, 0, 0, 0),
--- a/docshell/shistory/nsSHEntryShared.h
+++ b/docshell/shistory/nsSHEntryShared.h
@@ -48,20 +48,20 @@ class Document;
  */
 class SHEntrySharedParentState {
  public:
   uint64_t GetID() const { return mID; }
 
   void NotifyListenersContentViewerEvicted();
 
  protected:
-  SHEntrySharedParentState(nsSHistory* aSHistory, uint64_t aID);
+  SHEntrySharedParentState(nsISHistory* aSHistory, uint64_t aID);
   SHEntrySharedParentState(SHEntrySharedParentState* aDuplicate, uint64_t aID)
       : SHEntrySharedParentState(aDuplicate->mSHistory, aID) {}
-  SHEntrySharedParentState(nsIWeakReference* aDuplicate, uint64_t aID);
+  SHEntrySharedParentState(nsIWeakReference* aSHistory, uint64_t aID);
   virtual ~SHEntrySharedParentState();
   NS_INLINE_DECL_VIRTUAL_REFCOUNTING_WITH_DESTROY(SHEntrySharedParentState,
                                                   Destroy())
 
   virtual void Destroy() { delete this; }
 
   void CopyFrom(SHEntrySharedParentState* aSource);
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -3480,17 +3480,18 @@ bool ContentChild::DeallocPSessionStorag
 
 PSHEntryChild* ContentChild::AllocPSHEntryChild(
     PSHistoryChild* aSHistory, const PSHEntryOrSharedID& aEntryOrSharedID) {
   // We take a strong reference for the IPC layer. The Release implementation
   // for SHEntryChild will ask the IPC layer to release it (through
   // DeallocPSHEntryChild) if that is the only remaining reference.
   RefPtr<SHEntryChild> child;
   if (aEntryOrSharedID.type() == PSHEntryOrSharedID::Tuint64_t) {
-    child = new SHEntryChild(aEntryOrSharedID.get_uint64_t());
+    child = new SHEntryChild(static_cast<SHistoryChild*>(aSHistory),
+                             aEntryOrSharedID.get_uint64_t());
   } else {
     child = new SHEntryChild(
         static_cast<const SHEntryChild*>(aEntryOrSharedID.get_PSHEntryChild()));
   }
   return child.forget().take();
 }
 
 void ContentChild::DeallocPSHEntryChild(PSHEntryChild* aActor) {
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -923,17 +923,17 @@ parent:
 
     async PLoginReputation(URIParams formURI);
 
     async PSessionStorageObserver();
 
     async PSHistory(BrowsingContext aContext);
 
     // Clone from entry or use shared id.
-    sync PSHEntry(PSHistory shistory, PSHEntryOrSharedID entryOrSharedID);
+    sync PSHEntry(nullable PSHistory shistory, PSHEntryOrSharedID entryOrSharedID);
 
     async PBenchmarkStorage();
 
     // Services remoting
 
     async StartVisitedQuery(URIParams uri);
     async SetURITitle(URIParams uri, nsString title);